Skip to main content

HDRezka

PyPI version Downloads Python versions License GitHub stars

Async Python client for HDRezka. Designed for scripts and for multi-user backends (one HDRezkaClient instance per user / request scope).

Disclaimer

This is an unofficial library. It is meant for personal tooling and backends built by people who already have the right to use HDRezka under the service's own rules and under applicable law. Please read and follow the terms published by HDRezka (they change over time). Among other things, bots, downloaders, parsers, scraping, and many third-party clients may be restricted or may require Premium; access can be limited without notice. Use only what you are allowed to use, and only within those limits. This project does not endorse misuse of the service, account sharing, or anything that harms the platform or other users.

Default host is https://rezka.ag/ (free viewing is described there in the service rules). In practice most public mirrors sit behind Cloudflare, and a plain scripted client often gets blocked. You can point host= at another mirror (see mirrors.txt), use a suitable network path, and keep browser-like TLS impersonation enabled (default). That may help reliability; it is not a guarantee, and it is not permission to ignore the service rules.

Install

pip install hdrezka

Socks proxy support:

pip install hdrezka[socks]

Quick start

import asyncio
import os

from hdrezka import HDRezkaClient


async def main():
    async with HDRezkaClient() as client:
        await client.login(os.environ['LOGIN_NAME'], os.environ['LOGIN_PASSWORD'])

        items = await client.search('Breaking Bad').get_page(1)
        player = await client.player(items[0].url)
        # or: player = await Player(items[0].url, client=client)

        print(player.post.info)

        translator_id = None
        for name, id_ in player.post.translators.name_id.items():
            if 'субтитры' in name.casefold():
                translator_id = id_
                break

        stream = await player.get_stream(1, 1, translator_id)
        video = stream.video
        print(await video.last_url[-1])
        print(await video[video.min].last_url[0].mp4)

        subtitles = stream.subtitles
        if subtitles.has_subtitles:
            print(subtitles.default.url)


if __name__ == '__main__':
    asyncio.run(main())

HDRezkaClient

HDRezkaClient owns the HTTP session, active mirror (host), cookies, and a small player cache. Create a separate client for each user when building an API.

Method / property Purpose
await client.login(email, password) Discover an active mirror and authenticate
client.search(query) Bound Search
client.page(url=None) Bound catalog Page
client.favorites(cat_id=None) Bound Favorites page (/favorites/ or /favorites/{id}/)
await client.player(url) PlayerMovie or PlayerSeries
await client.post(url) Initialized Post
await client.navbar() Site top navigation map
await client.series_updates() Sidebar series update feed (home page)
await client.add_favorites_cat(name) Create a favorites collection
await client.rename_favorites_cat(cat_id, name) Rename a collection
await client.add_favorites_post(post_id, cat_id) Add a title to a collection
await client.remove_favorites_cat(cat_id) Delete a collection
client.ajax Bound AJAX helpers (streams, trailers, favorites, …)
client.host Current mirror base URL
await client.aclose() Close the HTTP client (also via async with)

Constructor options: host, proxy, http_client, request_kwargs, headers, redirect_url, impersonate.

Domain types (Search, Player, Post, Page, Favorites, AJAX) require an explicit client= (or are created through the client factories above).

Cloudflare and browser impersonation

By default HDRezkaClient sends browser-like headers and uses curl_cffi (via httpx-curl-cffi) so the TLS/HTTP2 fingerprint looks closer to a real browser. Turn it off or pick a target:

HDRezkaClient()                          # impersonate=True → Chrome
HDRezkaClient(impersonate='safari')      # specific curl_cffi target
HDRezkaClient(impersonate=False)         # plain httpx + browser-like headers

This only helps with fingerprint checks. JavaScript challenges (the “Just a moment…” interstitial), bad IPs, and account/policy limits are out of scope. Prefer a clean residential / personal path over free shared VPNs when the service blocks you. You can also paste browser cookies into the client after solving a challenge manually.

Navigation, filters, and sidebar

These parsers read whatever the HTML currently contains (no hardcoded genre lists). Missing blocks return empty structures.

Navbar

nav = await client.navbar()
for item in nav.items:
    print(item.name, item.url, item.single)
    if item.submenu:
        for genre in item.submenu.genres:
            print(' ', genre.name, genre.url)
        for collection in item.submenu.collections:
            print(' ', collection.name, collection.url, collection.classes)
        if item.submenu.find_best:
            print(' ', item.submenu.find_best.categories, item.submenu.find_best.years)

You can also parse from any page: await client.page().get_navbar(), or call parse_navbar(html) on a saved HTML string / BeautifulSoup tree.

Catalog filters and sorting

On category/genre pages, ul.b-content__main_filters exposes sort links (filter=) and content-type links (genre=).

page = client.page('/films/')
filters = await page.get_filters()
for link in filters.sorts:
    print(link.name, link.param, link.value, link.active)
for link in filters.types:
    print(link.name, link.param, link.value, link.active)

# Apply a filter when fetching titles
items = await page.get_page(1, filter='popular', genre=1)

# Or get titles + filters + updates in one response
content = await page.get_page_content(1, filter='watching')
print(content.filters, content.series_updates)

Series updates (sidebar)

for block in await client.series_updates():
    print(block.date)
    for row in block.items:
        print(row.name, row.url, row.season, row.episode, row.translation)

Post schedule

Many series pages include .b-post__schedule tables (air dates per season). They are parsed when you await a Post:

post = await client.post(url)
for block in post.schedule:
    print(block.title)
    for row in block.items:
        print(row.season, row.episode, row.title, row.date, row.exists)

Or call parse_schedule(html) on saved HTML / a BeautifulSoup tree.

Favorites (collections)

Favorites require login. Mutations go through POST /ajax/favorites/; browsing uses the normal Page flow on /favorites/[id].

async with HDRezkaClient() as client:
    await client.login(email, password)

    # Create a collection in the profile
    created = await client.add_favorites_cat('Смотрю')
    cat_id = created['id']

    # Rename
    await client.rename_favorites_cat(cat_id, 'Не буду смотреть')

    # Add a title (post id from Post / Player)
    post = await client.post('series/thriller/646-vo-vse-tyazhkie-2008.html')
    await client.add_favorites_post(post.id, cat_id)

    # Browse the collection (same pagination / InlineItem API as other pages)
    fav = client.favorites(cat_id)
    titles = await fav.get_page(1)
    cats = await fav.get_cats()  # a.b-favorites_content__cats_list_link
    for cat in cats:
        print(cat.id, cat.name, cat.count, cat.url)

    # Remove the collection
    await client.remove_favorites_cat(cat_id)

Equivalent low-level calls: client.ajax.add_favorites_cat, rename_favorites_cat, add_favorites_post, remove_favorites_cat.

Login and mirrors

Create an HDRezka account only if the service allows it for your case. If registration is disabled, try the flows they document (for example social login and setting a password). Premium and third-party clients are governed by their rules, not by this library.

login requests the standby URL (default https://standby-rezka.tv/), follows the redirect to an active mirror, posts credentials to /ajax/login/, updates client.host, and stores cookies on that client only.

You can set a mirror without login:

client = HDRezkaClient(host='https://hdrezka.tv/')

Many domains are behind Cloudflare; see mirrors.txt. Working access depends on mirror choice, IP reputation, and impersonation — not on the library claiming any special relationship with the site.

Default constants (not shared session state):

from hdrezka.url import Request, DEFAULT_HOST, DEFAULT_REDIRECT_URL

Proxies

from hdrezka import HDRezkaClient

client = HDRezkaClient(proxy='socks5://localhost:9050')

Or pass your own httpx.AsyncClient as http_client= (the library will not close it).

Migration from 4.x

Version 5 removes process-global session state.

4.x 5.x
await login_global(email, password) await client.login(email, password)
DEFAULT_CLIENT / DEFAULT_REQUEST_KWARGS HDRezkaClient(...) / request_kwargs=
Mutating Request.HOST for the process client.host or HDRezkaClient(host=...)
Search('query') client.search('query') or Search('query', client=client)
await Player(url) await client.player(url) or await Player(url, client=client)
AJAX.get_stream(...) (classmethods) client.ajax.get_stream(...)

Parsing and stream logic are unchanged; wire everything through a client.

Documentation

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hdrezka-5.2.0.tar.gz (32.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hdrezka-5.2.0-py3-none-any.whl (42.9 kB view details)

Uploaded Python 3

File details

Details for the file hdrezka-5.2.0.tar.gz.

File metadata

  • Download URL: hdrezka-5.2.0.tar.gz
  • Upload date:
  • Size: 32.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.13.14 Linux/7.1.3-zen2

File hashes

Hashes for hdrezka-5.2.0.tar.gz
Algorithm Hash digest
SHA256 1ac8c5e3b654653f6c56b58c0c2f1e1b0cddbbefa8dd5711c30ec1afd0c32853
MD5 6999843995b21c23ea89c70f3d0d36f9
BLAKE2b-256 a17e9eea1fb74a44b066f9405d0d895d62ce70f4b48e68129313a30cbb61807b

See more details on using hashes here.

File details

Details for the file hdrezka-5.2.0-py3-none-any.whl.

File metadata

  • Download URL: hdrezka-5.2.0-py3-none-any.whl
  • Upload date:
  • Size: 42.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.13.14 Linux/7.1.3-zen2

File hashes

Hashes for hdrezka-5.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 75ebfdc1ebd5b0fb0d1d80e32d544ed8b28441995e2372b3d94a78f509a9fd52
MD5 02c173b816c2b6ee782f5d5e2113c815
BLAKE2b-256 9bb2eae3921b268a48cf683538f3a510d7299bd8fbca036b296dd528c5671640

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

5.2.0 This release

2 files

5.1.0

2 files

5.0.0

2 files

4.0.4

2 files

4.0.3

2 files

4.0.2

2 files

4.0.1

2 files

4.0.0

2 files

3.3.1

2 files

3.3.0

2 files

3.2.3

2 files

3.2.2

2 files

3.2.1

2 files

3.2.0

2 files

3.1.2

2 files

3.1.1

2 files

3.1.0

2 files

3.0.3

2 files

3.0.2

2 files

3.0.1

2 files

3.0.0

2 files

2.0.1

2 files

2.0.0

2 files

1.1.3

2 files

1.1.2

2 files

1.1.1

2 files

1.1.0

2 files

1.0.0

2 files

0.0.2

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page