Пример #1
0
    def to_normal_song(song_id: int, server_style: bool = True) -> ExtDict:
        if server_style:
            cases = _cases
        else:
            cases = {number + 1: value for number, value in _cases.items()}

        # get author and name, just like gd does
        author, name = cases.get(song_id, ("DJVI", "Unknown"))
        return ExtDict(name=name, author=author, id=song_id, size=0.0, links={}, custom=False)
Пример #2
0
def extract_info_from_endpoint(text: str) -> ExtDict:
    artist, whitelisted, scouted, song, api, *_ = filter(
        is_not_empty, re.split(r"</?br>", text))
    return ExtDict(
        artist=artist.split("Artist: ").pop(),
        song=song.split("Song: ").pop(),
        whitelisted=check_not(whitelisted),
        scouted=check_not(scouted),
        api=check_not(api),
    )
Пример #3
0
def extract_users(text: str) -> List[ExtDict]:
    tree, result = html_parse(text), []

    for a in tree.findall(r'.//div[@class="item-details-main"]/h4/a'):
        url = URL(a.attrib["href"]).with_scheme("https")
        name = a.text

        result.append(ExtDict(link=url, name=name))

    return result
Пример #4
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
Пример #5
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
Пример #6
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
Пример #7
0
    async def get_ng_song(self, song_id: int = 0) -> ExtDict:
        # just like get_song(), but gets anything available on NG.
        link = Route.NEWGROUNDS_SONG_LISTEN + str(song_id)

        content = await self.http.normal_request(link)
        html = content.decode().replace("\\", "")

        try:
            info = find_song_info(html)
        except ValueError:
            raise MissingAccess(f"Song was not found by ID: {song_id}") from None

        return ExtDict(
            name=info.name,
            author=info.author,
            id=song_id,
            size=round(info.size / 1024 / 1024, 2),
            links=dict(normal=link, download=info.link),
            custom=True,
        )
Пример #8
0
def extract_user_songs(
    json: Dict[str, Dict[str, Dict[str, Union[Dict[str, str], List[str]]]]]
) -> List[ExtDict]:
    result = []

    try:
        years = json["years"].values()
    except (TypeError, AttributeError):  # not found
        return result

    for entry in chain.from_iterable(year["items"] for year in years):
        tree = html_parse(entry)
        a = tree.findall(r'.//a[@class="item-link"]')[0]

        url = URL(a.attrib["href"]).with_scheme("https")
        song_id = int(url.parts[-1])

        name = a.attrib["title"]

        result.append(
            ExtDict(id=song_id, name=name, links={"normal": str(url)}))

    return result
Пример #9
0
def search_song_data(text: str) -> List[ExtDict]:
    tree, result = html_parse(text), []

    for a, div in zip(
            tree.findall(r'.//a[@class="item-audiosubmission"]'),
            tree.findall(r'.//div[@class="detail-title"]'),
    ):
        url = URL(a.attrib["href"]).with_scheme("https")
        song_id = int(url.parts[-1])

        h4, span, *_ = div.getchildren()

        name = switch_if_none(h4.text, "") + "".join(
            switch_if_none(mark.text, "") + switch_if_none(mark.tail, "")
            for mark in h4.getchildren())
        author = span.getchildren()[0].text

        result.append(
            ExtDict(id=song_id,
                    name=name,
                    author=author,
                    links={"normal": str(url)}))

    return result
Пример #10
0
 def parse_dict(self) -> ExtDict:
     return ExtDict(
         {k: getattr(self, k)
          for k in ("name", "id", "account_id")})
Пример #11
0
    async def search_levels_on_page(
        self,
        page: int = 0,
        query: str = "",
        filters: Optional[Filters] = None,
        user_id: Optional[int] = None,
        gauntlet: Optional[int] = None,
        *,
        exclude: Tuple[Type[BaseException]] = (),
        client: Client,
    ) -> Tuple[List[ExtDict], List[ExtDict], List[ExtDict]]:
        # levels, creators, songs
        if filters is None:
            filters = Filters.setup_empty()

        params = (
            Params()
            .create_new()
            .put_definer("search", query)
            .put_page(page)
            .put_total(0)
            .put_filters(filters)
        )
        codes = {-1: MissingAccess("No levels were found.")}
        if filters.strategy == SearchStrategy.BY_USER:

            if user_id is None:
                check_logged_obj(client, "search_levels_on_page(...)")

                user_id = client.id

                params.put_definer("accountid", client.account_id).put_password(client.encodedpass)
                params.put_local(1)

            params.put_definer("search", user_id)  # override the 'str' parameter in request

        elif filters.strategy == SearchStrategy.FRIENDS:
            check_logged_obj(client, "search_levels_on_page(..., client=client)")
            params.put_definer("accountid", client.account_id).put_password(client.encodedpass)

        if gauntlet is not None:
            params.put_definer("gauntlet", gauntlet)

        payload = params.finish()

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

        if not resp:
            return [], [], []

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

        lvdata, cdata, sdata = resp[:3]

        songs = list(map(parser.parse, filter(is_not_empty, sdata.split("~:~"))))

        creators = [
            ExtDict(zip(("id", "name", "account_id"), creator.split(":")))
            for creator in filter(is_not_empty, cdata.split("|"))
        ]

        parser.with_split(":").add_ext({"101": 0, "102": -1, "103": -1})

        levels = list(map(parser.parse, filter(is_not_empty, lvdata.split("|"))))

        return levels, creators, songs