Ejemplo n.º 1
0
    async def get_user(self, account_id: int = 0, return_only_stats: bool = False) -> ExtDict:
        payload = Params().create_new().put_definer("user", account_id).finish()
        codes = {-1: MissingAccess(f"No users were found with ID: {account_id}.")}

        resp = await self.http.request(Route.GET_USER_INFO, payload, error_codes=codes)
        mapped = Parser().with_split(":").should_map().parse(resp)

        if return_only_stats:
            return mapped

        another = (
            Params()
            .create_new()
            .put_definer("search", mapped.getcast(Index.USER_PLAYER_ID, 0, int))
            .put_total(0)
            .put_page(0)
            .finish()
        )
        some_resp = await self.http.request(Route.USER_SEARCH, another)

        new_resp = (
            Parser().split("#").take(0).check_empty().split(":").should_map().parse(some_resp)
        )

        if new_resp is None:
            raise codes.get(-1)

        mapped.update(
            {k: new_resp.get(k) for k in (Index.USER_NAME, Index.USER_ICON, Index.USER_ICON_TYPE)}
        )

        return mapped
Ejemplo n.º 2
0
    async def search_user(self, query: Union[int, str], return_abstract: bool = False) -> ExtDict:

        payload = (
            Params().create_new().put_definer("search", query).put_total(0).put_page(0).finish()
        )
        codes = {-1: MissingAccess(f"Searching for {query!r} failed.")}

        resp = await self.http.request(Route.USER_SEARCH, payload, error_codes=codes)
        mapped = Parser().split("#").take(0).check_empty().split(":").should_map().parse(resp)

        if mapped is None:
            raise codes.get(-1)

        account_id = mapped.getcast(Index.USER_ACCOUNT_ID, 0, int)

        if return_abstract or not account_id:
            return mapped

        # ok; if we should not return abstract, let's find all other parameters
        payload = Params().create_new().put_definer("user", account_id).finish()

        resp = await self.http.request(Route.GET_USER_INFO, payload, error_codes=codes)
        mapped.update(Parser().with_split(":").should_map().parse(resp))

        return mapped
Ejemplo n.º 3
0
    async def get_level_info(self, level_id: int = 0) -> Tuple[ExtDict, ExtDict, ExtDict]:
        # level data, creator, song
        assert level_id >= -2, "Invalid Level ID provided."

        if level_id < 0:
            type, number, cooldown = await self.get_timely_info(level_id)
        else:
            type, number, cooldown = 0, -1, -1

        ext = {"101": type, "102": number, "103": cooldown}

        codes = {-1: MissingAccess(f"Failed to get a level. Given ID: {level_id}")}

        payload = Params().create_new().put_definer("levelid", level_id).finish()
        resp = await self.http.request(Route.DOWNLOAD_LEVEL, payload, error_codes=codes)

        level_data = Parser().split("#").take(0).split(":").add_ext(ext).should_map().parse(resp)

        real_id = level_data.getcast(Index.LEVEL_ID, 0, int)

        payload = (
            Params()
            .create_new()
            .put_definer("search", real_id)
            .put_filters(Filters.setup_empty())
            .finish()
        )
        resp = await self.http.request(Route.LEVEL_SEARCH, payload, error_codes=codes)

        if not resp or resp.count("#") < 2:
            raise codes.get(-1)

        data = resp.split("#")

        # getting song
        song_data = data[2]

        if not song_data:
            song = Converter.to_normal_song(level_data.getcast(Index.LEVEL_AUDIO_TRACK, 0, int))
        else:
            song = Parser().with_split("~|~").should_map().parse(song_data)

        # getting creator
        creator_data = data[1]

        if not creator_data:
            id, name, account_id = (0, "unknown", 0)
        else:
            id, name, account_id = creator_data.split(":")

        creator = ExtDict(id=id, name=name, account_id=account_id)

        return level_data, creator, song
Ejemplo n.º 4
0
    async def get_user_list(
        self, type: int = 0, *, exclude: Tuple[Type[BaseException]] = (), client: Client
    ) -> List[ExtDict]:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_type(type)
            .finish()
        )
        codes = {
            -1: MissingAccess("Failed to fetch a user list."),
            -2: NothingFound("gd.AbstractUser"),
        }

        resp = await self.http.request(
            Route.GET_USER_LIST, payload, error_codes=codes, exclude=exclude
        )

        if resp is None:
            return []

        resp, parser = resp.split("|"), Parser().with_split(":").should_map()

        return list(map(parser.parse, resp))
Ejemplo n.º 5
0
    async def rate_level(self, level_id: int, rating: int, *, client: Client) -> None:
        assert 0 < rating <= 10, "Invalid star value given."

        rs, udid, uuid = Coder.gen_rs(), Params.gen_udid(), Params.gen_uuid()
        values = [level_id, rating, rs, client.account_id, udid, uuid]
        chk = Coder.gen_chk(type="like_rate", values=values)

        payload = (
            Params()
            .create_new()
            .put_definer("levelid", level_id)
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_udid(udid)
            .put_uuid(uuid)
            .put_definer("stars", rating)
            .put_rs(rs)
            .put_chk(chk)
            .finish()
        )

        resp = await self.http.request(Route.RATE_LEVEL_STARS, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to rate level by ID: {level_id}.")
Ejemplo n.º 6
0
    async def like(
        self, item_id: int, typeid: int, special: int, dislike: bool = False, *, client: Client
    ) -> None:
        like = dislike ^ 1

        rs, udid, uuid = Coder.gen_rs(), Params.gen_udid(), Params.gen_uuid()
        values = [special, item_id, like, typeid, rs, client.account_id, udid, uuid]
        chk = Coder.gen_chk(type="like_rate", values=values)

        payload = (
            Params()
            .create_new(game_version=20)
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_udid(udid)
            .put_uuid(uuid)
            .put_definer("itemid", item_id)
            .put_like(like)
            .put_type(typeid)
            .put_special(special)
            .put_rs(rs)
            .put_chk(chk)
            .finish()
        )

        resp = await self.http.request(Route.LIKE_ITEM, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to like an item by ID: {item_id}.")
Ejemplo n.º 7
0
    async def update_settings(
        self,
        message_policy: MessagePolicyType,
        friend_request_policy: FriendRequestPolicyType,
        comment_policy: CommentPolicyType,
        youtube: str,
        twitter: str,
        twitch: str,
        *,
        client: Client,
    ) -> None:
        payload = (
            Params()
            .create_new("web")
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_profile_upd(
                message_policy.value,
                friend_request_policy.value,
                comment_policy.value,
                youtube,
                twitter,
                twitch,
            )
            .finish_login()
        )
        resp = await self.http.request(Route.UPDATE_ACC_SETTINGS, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to update profile settings of a client: {client!r}.")
Ejemplo n.º 8
0
    async def load_save(self, client: Client) -> Tuple[Optional[api.Database], Optional[Save]]:
        link = Route.GD_URL

        payload = (
            Params()
            .create_new()
            .put_username(client.name)
            .put_definer("password", client.password)
            .finish_login()
        )
        codes = {-11: MissingAccess(f"Failed to load data for client: {client!r}.")}

        resp = await self.http.request(
            Route.LOAD_DATA, payload, error_codes=codes, custom_base=link
        )

        try:
            main, levels, *_ = resp.split(";")
            db = await api.save.from_string_async(main, levels, xor=False, follow_os=False)
            save = await SaveParser.aio_parse(db.main.dump())

            return db, save

        except Exception:
            return None, None
Ejemplo n.º 9
0
    async def get_page_messages(
        self,
        sent_or_inbox: str,
        page: int,
        *,
        exclude: Tuple[Type[BaseException]] = (),
        client: Client,
    ) -> List[ExtDict]:
        assert sent_or_inbox in ("inbox", "sent")
        inbox = 0 if sent_or_inbox != "sent" else 1

        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_page(page)
            .put_total(0)
            .get_sent(inbox)
            .finish()
        )
        codes = {-1: MissingAccess("Failed to get messages."), -2: NothingFound("gd.Message")}

        resp = await self.http.request(
            Route.GET_PRIVATE_MESSAGES, payload, error_codes=codes, exclude=exclude
        )
        resp = Parser().split("#").take(0).check_empty().split("|").parse(resp)

        if resp is None:
            return []

        parser = Parser().with_split(":").should_map()
        return list(map(parser.parse, resp))
Ejemplo n.º 10
0
 async def get_song(self, song_id: int = 0) -> ExtDict:
     payload = Params().create_new().put_definer("song", song_id).finish()
     codes = {
         -1: MissingAccess(f"No songs were found with ID: {song_id}."),
         -2: SongRestrictedForUsage(song_id),
     }
     resp = await self.http.request(Route.GET_SONG_INFO, payload, error_codes=codes)
     return Parser().with_split("~|~").should_map().parse(resp)
Ejemplo n.º 11
0
    async def get_gauntlets(self) -> List[ExtDict]:
        payload = Params().create_new().finish()

        resp = await self.http.request(Route.GET_GAUNTLETS, payload)

        splitted = Parser().split("#").take(0).split("|").parse(resp)
        parser = Parser().with_split(":").should_map()

        return list(map(parser.parse, filter(is_not_empty, splitted)))
Ejemplo n.º 12
0
    async def unfriend_user(self, account_id: int, *, client: Client) -> None:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_definer("user", account_id)
            .finish()
        )
        resp = await self.http.request(Route.REMOVE_FRIEND, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to unfriend a user by Account ID: {account_id!r}.")
Ejemplo n.º 13
0
    async def read_friend_request(self, request_id: int, client: Client) -> None:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_definer("requestid", request_id)
            .finish()
        )
        resp = await self.http.request(Route.READ_REQUEST, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to read a friend request by ID: {request_id!r}.")
Ejemplo n.º 14
0
    async def delete_level(self, level_id: int, *, client: Client) -> None:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_definer("levelid", level_id)
            .put_password(client.encodedpass)
            .finish_level()
        )

        resp = await self.http.request(Route.DELETE_LEVEL, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to delete a level by ID: {level_id}.")
Ejemplo n.º 15
0
    async def get_leaderboard(
        self, level_id: int, strategy: LevelLeaderboardStrategy, *, client: Client
    ) -> List[ExtDict]:
        # timely_type: TimelyType, played: bool = False, timely_index: int = 0, percentage: int = 0,
        # jumps: int = 0, attempts: int = 0, seconds: int = 0, coins: int = 0
        # rs = Coder.gen_rs()
        # seed = Coder.gen_level_lb_seed(jumps, percentage, seconds, played)

        # if str(timely_type) == 'weekly':
        #     timely_index += 100000

        # values = [
        #     client.account_id, level_id, percentage, seconds, jumps, attempts,
        #     percentage, 100 - percentage, 1, coins, timely_index, rs
        # ]

        # chk = Coder.gen_chk(type='levelscore', values=values)

        params = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_definer("levelid", level_id)
            .put_password(client.encodedpass)
            .put_type(strategy.value)
        )

        # params.put_percent(percentage).put_chk(chk)

        # for index, value in enumerate((
        #     attempts + 8354, jumps + 3991, seconds + 4085, seed, random.randint(100, 10000),
        #     "", rs, attempts, coins + 5819, timely_index
        # ), 1):
        #     params.put_seed(value, prefix='s', suffix=index)

        payload = params.finish()

        codes = {-1: MissingAccess(f"Failed to get leaderboard of the level by ID: {level_id!r}.")}

        resp = await self.http.request(Route.GET_LEVEL_SCORES, payload, error_codes=codes)

        if not resp:
            return []

        resp, parser = (
            resp.split("|"),
            Parser().with_split(":").add_ext({"101": level_id}).should_map(),
        )

        return list(map(parser.parse, filter(is_not_empty, resp)))
Ejemplo n.º 16
0
    async def retrieve_page_comments(
        self,
        account_id: int,
        id: int,
        type: str = "profile",
        page: int = 0,
        *,
        strategy: CommentStrategy,
        exclude: Tuple[Type[BaseException]] = (),
    ) -> List[ExtDict]:
        assert isinstance(page, int) and page >= 0
        assert type in ("profile", "level")

        is_level = type == "level"

        typeid = is_level ^ 1
        definer = "userid" if is_level else "accountid"
        selfid = id if is_level else account_id
        route = Route.GET_COMMENT_HISTORY if is_level else Route.GET_ACC_COMMENTS

        parser = Parser().add_ext({"101": typeid}).should_map()

        if is_level:
            parser.split(":").take(0).split("~")
        else:
            parser.with_split("~")

        param_obj = Params().create_new().put_definer(definer, selfid).put_page(page).put_total(0)
        if is_level:
            param_obj.put_mode(strategy.value)
        payload = param_obj.finish()

        codes = {
            -1: MissingAccess(f"Failed to retrieve comment for user by Account ID: {account_id!r}.")
        }

        resp = await self.http.request(route, payload, error_codes=codes, exclude=exclude)

        if not resp:
            return []

        splitted = resp.split("#").pop(0)

        if not splitted:
            if issubclass(NothingFound, exclude):
                return []
            raise NothingFound("gd.Comment")

        return list(map(parser.parse, filter(is_not_empty, splitted.split("|"))))
Ejemplo n.º 17
0
    async def login(self, user: str, password: str) -> Tuple[int, int]:
        # account_id, id
        payload = (
            Params().create_new().put_login_definer(username=user, password=password).finish_login()
        )
        codes = {
            -1: LoginFailure(login=user, password=password),
            -12: MissingAccess(f"Account {user!r} (password {password!r}) is disabled."),
        }

        resp = await self.http.request(Route.LOGIN, payload, error_codes=codes)

        account_id, id, *junk = resp.split(",")

        return int(account_id), int(id)
Ejemplo n.º 18
0
    async def update_level_desc(self, level_id: int, content: str, *, client: Client) -> None:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_definer("levelid", level_id)
            .put_level_desc(content)
            .finish()
        )

        resp = await self.http.request(Route.UPDATE_LEVEL_DESC, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to update description of the level by ID: {level_id}.")
Ejemplo n.º 19
0
    async def test_song(self, song_id: int = 0) -> ExtDict:
        codes = {-1: MissingAccess(f"Failed to fetch artist info for ID: {song_id}")}
        payload = Params().create_new("web").put_definer("song", song_id).close()
        resp = await self.http.request(
            Route.TEST_SONG, params=payload, method="get", error_codes=codes
        )

        data = ExtDict(id=song_id)

        try:
            data.update(extract_info_from_endpoint(resp))
        except ValueError:
            raise MissingAccess(f"Failed to load data. Response: {resp!r}.") from None

        return data
Ejemplo n.º 20
0
    async def get_level_comments(
        self,
        level_id: int,
        strategy: CommentStrategy,
        amount: int,
        exclude: Tuple[Type[BaseException]] = (),
    ) -> List[Tuple[ExtDict, ExtDict]]:
        # comment, user
        payload = (
            Params()
            .create_new()
            .put_definer("levelid", level_id)
            .put_page(0)
            .put_total(0)
            .put_mode(strategy.value)
            .put_count(amount)
            .finish()
        )
        codes = {
            -1: MissingAccess(f"Failed to get comments of a level by ID: {level_id!r}."),
            -2: NothingFound("gd.Comment"),
        }

        resp = await self.http.request(
            Route.GET_COMMENTS, payload, error_codes=codes, exclude=exclude
        )

        if resp is None:
            return []

        splitted = Parser().split("#").take(0).split("|").parse(resp)
        parser = Parser().with_split("~").should_map()

        res = []

        for elem in filter(is_not_empty, splitted):
            com_data, user_data, *_ = map(parser.parse, elem.split(":"))
            com_data.update({"1": level_id, "101": 0, "102": 0})

            user_data = ExtDict(
                account_id=user_data.getcast(Index.USER_ACCOUNT_ID, 0, int),
                id=com_data.getcast(Index.COMMENT_AUTHOR_ID, 0, int),
                name=user_data.get(Index.USER_NAME, "unknown"),
            )

            res.append((com_data, user_data))

        return res
Ejemplo n.º 21
0
    async def delete_message(
        self, typeof: MessageOrRequestType, message_id: int, client: Client
    ) -> None:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_definer("messageid", message_id)
            .put_password(client.encodedpass)
            .put_is_sender(typeof.name.lower())
            .finish()
        )
        resp = await self.http.request(Route.DELETE_PRIVATE_MESSAGE, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to delete a message by ID: {message_id!r}.")
Ejemplo n.º 22
0
    async def post_comment(self, content: str, *, client: Client) -> None:
        to_gen = [client.name, 0, 0, 1]

        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_username(client.name)
            .put_password(client.encodedpass)
            .put_comment(content, to_gen)
            .comment_for("profile")
            .finish()
        )
        codes = {-1: MissingAccess("Failed to post a comment.")}

        await self.http.request(Route.UPLOAD_ACC_COMMENT, payload, error_codes=codes)
Ejemplo n.º 23
0
    async def block_user(self, account_id: int, unblock: bool = False, *, client: Client) -> None:
        route = Route.UNBLOCK_USER if unblock else Route.BLOCK_USER
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_definer("user", account_id)
            .finish()
        )
        resp = await self.http.request(route, payload)

        if resp != 1:
            raise MissingAccess(
                f"Failed to {'un' if unblock else ''}block a user by Account ID: {account_id!r}."
            )
Ejemplo n.º 24
0
    async def update_profile(self, settings: Dict[str, int], *, client: Client) -> None:
        settings_cased = {Converter.snake_to_camel(name): value for name, value in settings.items()}

        rs = Coder.gen_rs()

        req_chk_params = [client.account_id]
        req_chk_params.extend(
            settings.get(param, 0)
            for param in (
                "user_coins",
                "demons",
                "stars",
                "coins",
                "icon_type",
                "icon",
                "diamonds",
                "acc_icon",
                "acc_ship",
                "acc_ball",
                "acc_bird",
                "acc_dart",
                "acc_robot",
                "acc_glow",
                "acc_spider",
                "acc_explosion",
            )
        )

        chk = Coder.gen_chk(type="userscore", values=req_chk_params)

        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .put_username(client.name)
            .put_seed(rs)
            .put_seed(chk, suffix=str(2))
            .finish()
        )

        payload.update(settings_cased)

        resp = await self.http.request(Route.UPDATE_USER_SCORE, payload)

        if not resp > 0:
            raise MissingAccess(f"Failed to update profile of a client: {client!r}")
Ejemplo n.º 25
0
    async def read_message(
        self, typeof: MessageOrRequestType, message_id: int, client: Client
    ) -> str:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_definer("messageid", message_id)
            .put_is_sender(typeof.name.lower())
            .put_password(client.encodedpass)
            .finish()
        )
        codes = {-1: MissingAccess(f"Failed to read a message by ID: {message_id!r}.")}
        resp = await self.http.request(Route.READ_PRIVATE_MESSAGE, payload, error_codes=codes,)
        mapped = Parser().with_split(":").should_map().parse(resp)

        return Coder.decode(type="message", string=mapped.get(Index.MESSAGE_BODY, ""))
Ejemplo n.º 26
0
    async def get_page_map_packs(
        self, page: int = 0, *, exclude: Tuple[Type[BaseException]] = (),
    ) -> List[ExtDict]:
        payload = Params().create_new().put_page(page).finish()

        resp = await self.http.request(Route.GET_MAP_PACKS, payload)

        splitted = Parser().split("#").take(0).split("|").check_empty().should_map().parse(resp)

        if not splitted:
            if issubclass(NothingFound, exclude):
                return []
            raise NothingFound("gd.MapPack")

        parser = Parser().with_split(":").should_map()

        return list(map(parser.parse, splitted))
Ejemplo n.º 27
0
    async def delete_friend_request(
        self, typeof: MessageOrRequestType, user_id: int, client: Client
    ) -> None:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_definer("user", user_id)
            .put_password(client.encodedpass)
            .put_is_sender(typeof.name.lower())
            .finish()
        )
        resp = await self.http.request(Route.DELETE_REQUEST, payload)

        if resp != 1:
            raise MissingAccess(
                f"Failed to delete a friend request by User (with ID): {user_id!r}."
            )
Ejemplo n.º 28
0
    async def delete_comment(
        self, typeof: CommentType, comment_id: int, level_id: int, *, client: Client
    ) -> None:
        cases = {0: Route.DELETE_LEVEL_COMMENT, 1: Route.DELETE_ACC_COMMENT}
        route = cases.get(typeof.value)
        payload = (
            Params()
            .create_new()
            .put_definer("commentid", comment_id)
            .put_definer("accountid", client.account_id)
            .put_password(client.encodedpass)
            .comment_for(typeof.name.lower(), level_id)
            .finish()
        )
        resp = await self.http.request(route, payload)

        if resp != 1:
            raise MissingAccess(f"Failed to delete a comment by ID: {comment_id!r}.")
Ejemplo n.º 29
0
    async def send_message(
        self, account_id: int, subject: str, body: str, *, client: Client
    ) -> None:
        payload = (
            Params()
            .create_new()
            .put_definer("accountid", client.account_id)
            .put_message(subject, body)
            .put_recipient(account_id)
            .put_password(client.encodedpass)
            .finish()
        )
        resp = await self.http.request(Route.SEND_PRIVATE_MESSAGE, payload)

        if resp != 1:
            raise MissingAccess(
                f"Failed to send a message to a user by Account ID: {account_id!r}."
            )
Ejemplo n.º 30
0
    async def get_timely_info(self, type_id: int = -1) -> Tuple[int, int, int]:
        # Daily: -1, Weekly: -2
        weekly = ~type_id
        payload = Params().create_new().put_weekly(weekly).finish()
        codes = {-1: MissingAccess(f"Failed to fetch a {type!r} level.")}
        resp = await self.http.request(Route.GET_TIMELY, payload, error_codes=codes)

        try:
            number, cooldown, *_ = map(int, resp.split("|"))
        except ValueError:  # unpacking failed or something else
            raise MissingAccess(
                "Failed to fetch a timely level. Most likely it is being refreshed."
            ) from None

        number %= 100000
        weekly += 1

        return (weekly, number, cooldown)