ymdantic 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ymdantic-0.2.2/.github/workflows/tests.yml +104 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/.pre-commit-config.yaml +5 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/PKG-INFO +1 -1
- {ymdantic-0.2.1 → ymdantic-0.2.2}/pyproject.toml +1 -1
- {ymdantic-0.2.1 → ymdantic-0.2.2}/uv.lock +1 -1
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/client/session/aiohttp_client.py +62 -3
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/client/yandex_music.py +12 -6
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/search/base.py +16 -1
- ymdantic-0.2.1/.github/workflows/tests.yml +0 -40
- {ymdantic-0.2.1 → ymdantic-0.2.2}/.editorconfig +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/.github/workflows/pypi-release.yml +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/.gitignore +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/LICENSE +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/README.md +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/examples/chart.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/account/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/account/test_settings.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/conftest.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/search/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/search/test_search_instant_mixed.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/tracks/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/tracks/test_get_track.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/tracks/test_get_track_download_info.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/tracks/test_get_track_file_info.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/tests/tracks/test_get_tracks.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/adapters/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/adapters/pydantic_factory.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/adapters/to_camel.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/adapters/to_query_params.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/client/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/client/session/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/client/session/aiohttp_method.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/editorial_artists.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/editorial_compilation.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/editorial_new_releases.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/editorial_promotion.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/language.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/open_playlist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/enums/special.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/exceptions/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/exceptions/custom_exceptions.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/mixins.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/account/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/account/settings.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/action_button.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/agent.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/albums/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/albums/album.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/albums/label.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/artist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/artist_data.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/artist_track_chart_position.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/band_link_scanner_link.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/concert.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/counts.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/description.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/extra_action.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/ratings.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/social_link.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/artists/video.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/base.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/chart_position.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/clips/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/clips/clip.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/concerts/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/concerts/city_case_forms.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/concerts/concert.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/content_restrictions.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/cover.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/custom_wave.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/derived_colors.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/error.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/album.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/artist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/chart.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/chart_block.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/cover.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/editorial/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/editorial/new_releases.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/editorial/response.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/in_style.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/liked_playlist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/open_playlist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/personal_playlist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/playlist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/promotion.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/skeleton_response.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tab_block.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tab_data.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tab_source.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tabs_block.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/skeleton/tabs_source.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/special.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/view_all_action.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing/waves.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing3/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing3/block.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing3/chart.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/landing3/menu.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/pager.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/playlists/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/playlists/cover.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/playlists/owner.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/playlists/playlist.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/playlists/tag.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/playlists/track.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/response.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/s3.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/search/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/search/results.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/theme.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/__init__.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/album.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/download_info.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/fade.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/file_info.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/lyrics_info.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/major.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/podcast.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/position.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/r128.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/tracks/track.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/models/trailer.py +0 -0
- {ymdantic-0.2.1 → ymdantic-0.2.2}/ymdantic/py.typed +0 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
name: Testing YMdantic
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
pull_request_target:
|
|
7
|
+
types: [opened, synchronize, reopened]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
if: github.event_name != 'pull_request_target'
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
17
|
+
check:
|
|
18
|
+
- name: Ruff format
|
|
19
|
+
cmd: ruff format --diff
|
|
20
|
+
- name: Ruff check
|
|
21
|
+
cmd: ruff check ymdantic tests
|
|
22
|
+
- name: Mypy
|
|
23
|
+
cmd: mypy ymdantic tests
|
|
24
|
+
|
|
25
|
+
name: "${{ matrix.check.name }} (py${{ matrix.python-version }})"
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v6
|
|
29
|
+
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@v7
|
|
32
|
+
with:
|
|
33
|
+
version: "0.9.17"
|
|
34
|
+
python-version: ${{ matrix.python-version }}
|
|
35
|
+
enable-cache: true
|
|
36
|
+
|
|
37
|
+
- name: Install deps
|
|
38
|
+
run: uv sync --locked --all-groups
|
|
39
|
+
|
|
40
|
+
- name: Run check
|
|
41
|
+
run: uv run ${{ matrix.check.cmd }}
|
|
42
|
+
|
|
43
|
+
test_push:
|
|
44
|
+
if: github.event_name == 'push'
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
strategy:
|
|
47
|
+
fail-fast: false
|
|
48
|
+
matrix:
|
|
49
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
50
|
+
|
|
51
|
+
name: "Pytest push (py${{ matrix.python-version }})"
|
|
52
|
+
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v6
|
|
55
|
+
|
|
56
|
+
- name: Install uv
|
|
57
|
+
uses: astral-sh/setup-uv@v7
|
|
58
|
+
with:
|
|
59
|
+
version: "0.9.17"
|
|
60
|
+
python-version: ${{ matrix.python-version }}
|
|
61
|
+
enable-cache: true
|
|
62
|
+
|
|
63
|
+
- name: Install deps
|
|
64
|
+
run: uv sync --locked --all-groups
|
|
65
|
+
|
|
66
|
+
- name: Run Pytest
|
|
67
|
+
env:
|
|
68
|
+
YM_TOKEN: ${{ secrets.YM_TOKEN }}
|
|
69
|
+
run: uv run pytest -vv tests
|
|
70
|
+
|
|
71
|
+
test_pr_approved:
|
|
72
|
+
if: github.event_name == 'pull_request_target'
|
|
73
|
+
runs-on: ubuntu-latest
|
|
74
|
+
environment: pull_requests
|
|
75
|
+
strategy:
|
|
76
|
+
fail-fast: false
|
|
77
|
+
matrix:
|
|
78
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
79
|
+
|
|
80
|
+
name: "Pytest PR approved (py${{ matrix.python-version }})"
|
|
81
|
+
|
|
82
|
+
permissions:
|
|
83
|
+
contents: read
|
|
84
|
+
pull-requests: read
|
|
85
|
+
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/checkout@v6
|
|
88
|
+
with:
|
|
89
|
+
ref: ${{ github.event.pull_request.head.sha }}
|
|
90
|
+
|
|
91
|
+
- name: Install uv
|
|
92
|
+
uses: astral-sh/setup-uv@v7
|
|
93
|
+
with:
|
|
94
|
+
version: "0.9.17"
|
|
95
|
+
python-version: ${{ matrix.python-version }}
|
|
96
|
+
enable-cache: true
|
|
97
|
+
|
|
98
|
+
- name: Install deps
|
|
99
|
+
run: uv sync --locked --all-groups
|
|
100
|
+
|
|
101
|
+
- name: Run Pytest
|
|
102
|
+
env:
|
|
103
|
+
YM_TOKEN: ${{ secrets.YM_TOKEN }}
|
|
104
|
+
run: uv run pytest -vv tests
|
|
@@ -3,7 +3,7 @@ import urllib.parse
|
|
|
3
3
|
from types import TracebackType
|
|
4
4
|
from typing import Any, Optional, Self
|
|
5
5
|
|
|
6
|
-
from aiohttp import ClientError, ClientSession, ClientTimeout, FormData
|
|
6
|
+
from aiohttp import ClientError, ClientSession, ClientTimeout, FormData, TCPConnector
|
|
7
7
|
from dataclass_rest.base_client import BaseClient
|
|
8
8
|
from dataclass_rest.exceptions import ClientLibraryError
|
|
9
9
|
from dataclass_rest.http_request import HttpRequest
|
|
@@ -22,14 +22,73 @@ class AiohttpClient(BaseClient):
|
|
|
22
22
|
session: Optional[ClientSession] = None,
|
|
23
23
|
headers: Optional[dict[str, Any]] = None,
|
|
24
24
|
timeout: Optional[ClientTimeout] = None,
|
|
25
|
+
proxy: Optional[str] = None,
|
|
25
26
|
) -> None:
|
|
26
27
|
super().__init__()
|
|
27
28
|
self.base_url = base_url
|
|
28
29
|
self.headers = headers or {}
|
|
30
|
+
self.proxy = proxy
|
|
31
|
+
self.timeout = timeout
|
|
29
32
|
|
|
30
|
-
self._session = session or
|
|
33
|
+
self._session = session or self._create_session(headers=headers)
|
|
34
|
+
|
|
35
|
+
def _create_session(self, headers: dict[str, Any] | None) -> ClientSession:
|
|
36
|
+
"""
|
|
37
|
+
Создает ClientSession с учетом прокси.
|
|
38
|
+
|
|
39
|
+
Поддерживает HTTP, HTTPS и SOCKS прокси (4, 4a, 5).
|
|
40
|
+
|
|
41
|
+
:param headers:
|
|
42
|
+
:return: aiohttp ClientSession.
|
|
43
|
+
"""
|
|
44
|
+
if self.proxy is None:
|
|
45
|
+
return ClientSession(
|
|
46
|
+
headers=headers,
|
|
47
|
+
timeout=self.timeout or ClientTimeout(total=0),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
from aiohttp_socks import ProxyConnector # noqa: PLC0415
|
|
52
|
+
except ImportError as e:
|
|
53
|
+
raise ImportError(
|
|
54
|
+
"Warning: aiohttp_socks not installed. "
|
|
55
|
+
"SOCKS proxies will not work. "
|
|
56
|
+
"Install with: pip install aiohttp_socks",
|
|
57
|
+
) from e
|
|
58
|
+
|
|
59
|
+
# Определяем тип прокси по схеме
|
|
60
|
+
proxy_lower = self.proxy.lower()
|
|
61
|
+
|
|
62
|
+
# SOCKS прокси (поддерживаются socks4, socks4a, socks5, socks5h)
|
|
63
|
+
if any(
|
|
64
|
+
scheme in proxy_lower
|
|
65
|
+
for scheme in ["socks4", "socks5", "socks5h", "socks4a"]
|
|
66
|
+
):
|
|
67
|
+
# Используем ProxyConnector для SOCKS
|
|
68
|
+
connector = ProxyConnector.from_url(self.proxy)
|
|
69
|
+
return ClientSession(
|
|
70
|
+
connector=connector,
|
|
71
|
+
headers=headers,
|
|
72
|
+
timeout=self.timeout or ClientTimeout(total=0),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# HTTP/HTTPS прокси
|
|
76
|
+
if proxy_lower.startswith(("http://", "https://")):
|
|
77
|
+
connector = TCPConnector()
|
|
78
|
+
return ClientSession(
|
|
79
|
+
connector=connector,
|
|
80
|
+
proxy=self.proxy,
|
|
81
|
+
headers=headers,
|
|
82
|
+
timeout=self.timeout or ClientTimeout(total=0),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Если схема не распознана, предполагаем HTTP
|
|
86
|
+
connector = TCPConnector()
|
|
87
|
+
return ClientSession(
|
|
88
|
+
connector=connector,
|
|
89
|
+
proxy=f"http://{self.proxy}",
|
|
31
90
|
headers=headers,
|
|
32
|
-
timeout=timeout or ClientTimeout(total=0),
|
|
91
|
+
timeout=self.timeout or ClientTimeout(total=0),
|
|
33
92
|
)
|
|
34
93
|
|
|
35
94
|
async def close(self) -> None:
|
|
@@ -51,6 +51,7 @@ from ymdantic.models import (
|
|
|
51
51
|
)
|
|
52
52
|
from ymdantic.models.account import AccountSettings, SetAccountSettingsParams
|
|
53
53
|
from ymdantic.models.landing.artist import LandingArtistItemData
|
|
54
|
+
from ymdantic.models.search.base import SearchParamsDict
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
class YMClient(AiohttpClient):
|
|
@@ -61,15 +62,20 @@ class YMClient(AiohttpClient):
|
|
|
61
62
|
token: str,
|
|
62
63
|
user_id: int | None = None,
|
|
63
64
|
base_url: str = "https://api.music.yandex.net/",
|
|
65
|
+
proxy: str | None = None, # Формат: scheme://login:password@ip:port
|
|
64
66
|
) -> None:
|
|
65
67
|
self.user_id = user_id
|
|
68
|
+
|
|
69
|
+
headers = {
|
|
70
|
+
"Accept": "application/json",
|
|
71
|
+
"Authorization": f"OAuth {token}",
|
|
72
|
+
"X-Yandex-Music-Client": "YandexMusicAndroid/24023621",
|
|
73
|
+
}
|
|
74
|
+
|
|
66
75
|
super().__init__(
|
|
67
76
|
base_url=base_url,
|
|
68
|
-
headers=
|
|
69
|
-
|
|
70
|
-
"Authorization": f"OAuth {token}",
|
|
71
|
-
"X-Yandex-Music-Client": "YandexMusicAndroid/24023621",
|
|
72
|
-
},
|
|
77
|
+
headers=headers,
|
|
78
|
+
proxy=proxy,
|
|
73
79
|
)
|
|
74
80
|
|
|
75
81
|
def _init_request_body_factory(self) -> FactoryProtocol:
|
|
@@ -441,7 +447,7 @@ class YMClient(AiohttpClient):
|
|
|
441
447
|
|
|
442
448
|
async def search_instant_mixed(
|
|
443
449
|
self,
|
|
444
|
-
**params: Unpack[
|
|
450
|
+
**params: Unpack[SearchParamsDict],
|
|
445
451
|
) -> SearchInstantMixedResponse:
|
|
446
452
|
response = await self.search_instant_mixed_request(
|
|
447
453
|
params=SearchParams(**params),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Annotated, Literal
|
|
1
|
+
from typing import Annotated, Literal, NotRequired, TypedDict
|
|
2
2
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
@@ -24,6 +24,21 @@ class SearchParams(YMPostBaseModel):
|
|
|
24
24
|
nocorrect: bool = False
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
class SearchParamsDict(TypedDict, total=False):
|
|
28
|
+
"""Fields for search function."""
|
|
29
|
+
|
|
30
|
+
text: str
|
|
31
|
+
with_likes_count: NotRequired[bool]
|
|
32
|
+
page: NotRequired[int]
|
|
33
|
+
page_size: NotRequired[int]
|
|
34
|
+
with_best_results: NotRequired[bool]
|
|
35
|
+
type: NotRequired[Literal["all"]]
|
|
36
|
+
filter: NotRequired[
|
|
37
|
+
Literal["track", "artist", "album", "playlist", "podcast", "book", "clip"]
|
|
38
|
+
]
|
|
39
|
+
nocorrect: NotRequired[bool]
|
|
40
|
+
|
|
41
|
+
|
|
27
42
|
class SearchFilter(YMBaseModel):
|
|
28
43
|
"""Фильтры для поиска."""
|
|
29
44
|
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
name: Testing YMdantic
|
|
2
|
-
|
|
3
|
-
on: push
|
|
4
|
-
|
|
5
|
-
jobs:
|
|
6
|
-
lint:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
strategy:
|
|
9
|
-
fail-fast: false
|
|
10
|
-
matrix:
|
|
11
|
-
python-version: ["3.12", "3.13", "3.14"]
|
|
12
|
-
check:
|
|
13
|
-
- name: Ruff format
|
|
14
|
-
cmd: ruff format --diff
|
|
15
|
-
- name: Ruff check
|
|
16
|
-
cmd: ruff check ymdantic tests
|
|
17
|
-
- name: Mypy
|
|
18
|
-
cmd: mypy ymdantic tests
|
|
19
|
-
- name: Pytest
|
|
20
|
-
cmd: pytest -vv tests
|
|
21
|
-
|
|
22
|
-
name: "${{ matrix.check.name }} (py${{ matrix.python-version }})"
|
|
23
|
-
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v6
|
|
26
|
-
|
|
27
|
-
- name: Install uv
|
|
28
|
-
uses: astral-sh/setup-uv@v7
|
|
29
|
-
with:
|
|
30
|
-
version: "0.9.17"
|
|
31
|
-
python-version: ${{ matrix.python-version }}
|
|
32
|
-
enable-cache: true
|
|
33
|
-
|
|
34
|
-
- name: Install deps
|
|
35
|
-
run: uv sync --locked --all-groups
|
|
36
|
-
|
|
37
|
-
- name: Run check
|
|
38
|
-
env:
|
|
39
|
-
YM_TOKEN: ${{ secrets.YM_TOKEN }}
|
|
40
|
-
run: uv run ${{ matrix.check.cmd }}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|