Module hdrezka.post.post

General post module.

Classes

class Post (url: str, *, client: HDRezkaClient)
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'

Stores information about a title page (post).

Need await.

:param url: Absolute or relative post URL. :param client: Session used for HTTP requests and host joining.

Instance variables

var client
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var franchises
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var id
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var info
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var name
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var schedule
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var translator_id
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var translators
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var type
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'
var url
Expand source code
class Post:
    """Stores information about a title page (post)."""
    __slots__ = (
        'url', 'translator_id', 'id', 'name', 'type', 'info',
        'translators', 'franchises', 'schedule', 'client',
    )

    def __init__(self, url: str, *, client: 'HDRezkaClient'):
        """
        Need await.

        :param url: Absolute or relative post URL.
        :param client: Session used for HTTP requests and host joining.
        """
        self.client = client
        if not urllib.parse.urlparse(url).hostname:
            url = client.host_join(url)
        self.url = url

    def __await__(self):
        """
        Async initialize, prepare attributes.
        Do not call twice!
        """
        response = yield from self.client.get_response('GET', self.url).__await__()
        soup = BeautifulSoup(response.text, builder=BUILDER)
        self.type = soup.find('meta', property='og:type')['content'].removeprefix('video.')
        self.translator_id = self._get_translator_id(soup)
        self.info = get_post_info(soup, url=self.url, client=self.client)
        self.translators = self._get_translators(soup)

        self.id = int(soup.find(id='post_id')['value'])
        self.name = soup.find(class_='b-post__title').text.strip()
        franchises_url = soup.find(class_='b-post__franchise_link_title')
        self.franchises = FranchiseInfo(
            url=franchises_url and franchises_url.attrs.get('href'),
            soup=soup,
            client=self.client,
        )
        self.schedule = parse_schedule(soup)
        return self

    def _get_translator_id(self, soup: BeautifulSoup) -> int | None:
        """self.type must exist"""
        init_cdn_obj = 'sof.tv.%s' % {'tv_series': 'initCDNSeriesEvents', 'movie': 'initCDNMoviesEvents'}[self.type]
        for script in soup.find_all(lambda tag: tag.name == 'script' and not tag.attrs and tag.string):
            if not (s := script.string):
                continue
            obj_i = s.find(init_cdn_obj)
            if obj_i != -1:
                s = s[obj_i + len(init_cdn_obj):].split(',', 2)[1].strip()
                if s.isnumeric():
                    return int(s)
        return None

    def _get_translators(self, soup: BeautifulSoup) -> Translators:
        arr = {i.text.strip(): int(i['data-translator_id']) for i in el.find_all(recursive=False) if i.text
               } if (el := soup.find(id='translators-list')) else {}
        if not arr:
            arr[self.info.translators[0]] = self.translator_id
        return Translators(arr)

    def __repr__(self):
        return f'{self.__class__.__qualname__}<{self.name!r}; {self.type!r}>'