okmusic-api 0.1.0__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.
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: okmusic-api
3
+ Version: 0.1.0
4
+ Summary: Неофициальный бронированный SDK для работы с музыкальным API Одноклассников (WMF) через jsessionid
5
+ Author-email: l0v3m0n3y <ffxckemweball@gmail.com>
6
+ Project-URL: Homepage, https://github.com/l0v3m0n3y/OkMusic
7
+ Project-URL: Bug Tracker, https://github.com/l0v3m0n3y/OkMusic/issues
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Multimedia :: Sound/Audio
12
+ Requires-Python: >=3.7
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: curl_cffi>=0.7.0
15
+
16
+ # okmusic-api
17
+
18
+ Неофициальный Python SDK для работы со скрытым музыкальным API Одноклассников (WMF).
19
+ Использует `curl_cffi` для идеального обхода TLS-фингерпринтинга (JA3/JA4) распределенной сети CDN Одноклассников.
20
+
21
+ ## Установка
22
+
23
+ ```bash
24
+ pip install okmusic-api
25
+ ```
26
+
27
+ ## Быстрый старт
28
+
29
+ ```python
30
+ from okmusic_api import OKMusicSDK
31
+
32
+ # Твой jsessionid из кук браузера
33
+ sdk = OKMusicSDK(jsessionid="kdCHNeSo76je139vgu...")
34
+
35
+ # Поиск
36
+ results = sdk.search("jesus avgn")
37
+
38
+ # Скачивание трека целиком на диск (без пустых файлов в 0 байт)
39
+ sdk.download_track(123286133220562, "jesus_vssha.mp3")
40
+ ```
@@ -0,0 +1,25 @@
1
+ # okmusic-api
2
+
3
+ Неофициальный Python SDK для работы со скрытым музыкальным API Одноклассников (WMF).
4
+ Использует `curl_cffi` для идеального обхода TLS-фингерпринтинга (JA3/JA4) распределенной сети CDN Одноклассников.
5
+
6
+ ## Установка
7
+
8
+ ```bash
9
+ pip install okmusic-api
10
+ ```
11
+
12
+ ## Быстрый старт
13
+
14
+ ```python
15
+ from okmusic_api import OKMusicSDK
16
+
17
+ # Твой jsessionid из кук браузера
18
+ sdk = OKMusicSDK(jsessionid="kdCHNeSo76je139vgu...")
19
+
20
+ # Поиск
21
+ results = sdk.search("jesus avgn")
22
+
23
+ # Скачивание трека целиком на диск (без пустых файлов в 0 байт)
24
+ sdk.download_track(123286133220562, "jesus_vssha.mp3")
25
+ ```
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "okmusic-api" # Имя для pip install okmusic-api
7
+ version = "0.1.0" # Начинаем историю релизов красиво с чистой 0.1.0
8
+ authors = [
9
+ { name = "l0v3m0n3y", email = "ffxckemweball@gmail.com" },
10
+ ]
11
+ description = "Неофициальный бронированный SDK для работы с музыкальным API Одноклассников (WMF) через jsessionid"
12
+ readme = "README.md"
13
+ requires-python = ">=3.7"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Topic :: Multimedia :: Sound/Audio",
19
+ ]
20
+ dependencies = [
21
+ "curl_cffi>=0.7.0", # Зависимость, которая пробивает TLS-защиту CDN
22
+ ]
23
+
24
+ [project.urls]
25
+ "Homepage" = "https://github.com/l0v3m0n3y/OkMusic"
26
+ "Bug Tracker" = "https://github.com/l0v3m0n3y/OkMusic/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,4 @@
1
+ from .sdk import OKMusicSDK
2
+
3
+ __all__ = ["OKMusicSDK"]
4
+ __version__ = "0.1.0"
@@ -0,0 +1,170 @@
1
+ from curl_cffi import requests
2
+ from typing import Optional, Dict, Any
3
+ import hashlib
4
+ import re
5
+ import json
6
+
7
+
8
+ class OKMusicSDK:
9
+ def __init__(self, jsessionid: str):
10
+ self.jsessionid = jsessionid
11
+ self.base_url = "https://wmf.ok.ru"
12
+
13
+ self.session = requests.Session(impersonate="chrome")
14
+
15
+ self.common_headers = {
16
+ "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/155.0.0.0 Safari/537.36",
17
+ "Accept-Language": "ru-RU,ru;q=0.9,en;q=0.8",
18
+ "Origin": "https://ok.ru",
19
+ "sec-ch-ua": '"Google Chrome";v="155", "Chromium";v="155", "Not(A:Brand";v="24"',
20
+ "sec-ch-ua-mobile": "?0",
21
+ "sec-ch-ua-platform": '"Linux"',
22
+ }
23
+ self.session.headers.update(self.common_headers)
24
+
25
+ self.session.cookies.set("jsessionid", self.jsessionid, domain=".ok.ru")
26
+ self.session.cookies.set("jsessionid", self.jsessionid, domain=".okcdn.ru")
27
+ self.session.cookies.set("jsessionid", self.jsessionid, domain="wmf.ok.ru")
28
+
29
+ # Массив из JS
30
+ self._m = [4, 3, 5, 6, 1, 2, 8, 7, 2, 9, 3, 5, 7, 1, 4, 8, 8, 3, 4, 3, 1, 7, 3, 5, 9, 8, 1, 4, 3, 7, 2, 8]
31
+
32
+ def _generate_client_hash(self, stream_url: str) -> str:
33
+ """Генерирует clientHash по алгоритму из shared.js"""
34
+ match = re.search(r"md5=([0-9a-fA-F]+)", stream_url)
35
+ if not match:
36
+ raise ValueError("md5 не найден в URL")
37
+
38
+ md5_value = match.group(1)
39
+ # MD5(md5 + "secret")
40
+ hashed = hashlib.md5((md5_value + "secret").encode()).hexdigest()
41
+
42
+ # Сумма всех hex-цифр
43
+ a = sum(int(ch, 16) for ch in hashed)
44
+
45
+ result = []
46
+ length = len(hashed)
47
+ for c in range(length):
48
+ u = int(hashed[c], 16)
49
+ n = u if c == length - 1 else int(hashed[c + 1], 16)
50
+ result.append(str(abs(a - u * n * self._m[c])))
51
+
52
+ return "".join(result)
53
+
54
+ def _add_client_hash(self, stream_url: str) -> str:
55
+ if "clientHash=" in stream_url:
56
+ return stream_url
57
+ client_hash = self._generate_client_hash(stream_url)
58
+ return f"{stream_url}&client=web&clientHash={client_hash}"
59
+
60
+ def get_stream_link(self, track_id: int, ctx: str = "my|1") -> str:
61
+ url = f"{self.base_url}/play;jsessionid={self.jsessionid}"
62
+
63
+ params = {
64
+ "tid": track_id,
65
+ "ctx": ctx,
66
+ "client": "web",
67
+ "locale": "ru",
68
+ "imgfmt": "base",
69
+ }
70
+
71
+ headers = {
72
+ **self.common_headers,
73
+ "Accept": "application/json, text/javascript, */*; q=0.01",
74
+ "Content-Type": "application/x-www-form-urlencoded",
75
+ "Referer": "https://ok.ru/music/profile/910722294189",
76
+ "X-Requested-With": "XMLHttpRequest",
77
+ }
78
+
79
+ try:
80
+ response = self.session.post(
81
+ url,
82
+ params=params,
83
+ data="",
84
+ headers=headers,
85
+ timeout=20,
86
+ )
87
+
88
+ print(f"[OKMusic] play → {response.status_code}")
89
+
90
+ if response.status_code != 200:
91
+ print(response.text[:400])
92
+ return ""
93
+
94
+ data = response.json()
95
+ stream_url = data.get("play", "")
96
+
97
+ if not stream_url:
98
+ print("[OKMusic] Нет поля play в ответе:", data)
99
+ return ""
100
+
101
+ # Добавляем правильно сгенерированный clientHash
102
+ return self._add_client_hash(stream_url)
103
+
104
+ except Exception as e:
105
+ print(f"[OKMusic] Ошибка get_stream_link: {e}")
106
+ return ""
107
+
108
+ def download_track(self, track_id: int, output_filename: str = "track.mp3") -> bool:
109
+ stream_url = self.get_stream_link(track_id)
110
+ if not stream_url:
111
+ return False
112
+
113
+ print(f"[OKMusic] Скачиваем:\n{stream_url}\n")
114
+
115
+ headers = {
116
+ **self.common_headers,
117
+ "Accept": "*/*",
118
+ "Accept-Encoding": "identity",
119
+ "Referer": "https://ok.ru/music/profile/910722294189",
120
+ "sec-fetch-dest": "audio",
121
+ "sec-fetch-mode": "no-cors",
122
+ "sec-fetch-site": "cross-site",
123
+ "Range": "bytes=0-",
124
+ }
125
+
126
+ try:
127
+ response = self.session.get(
128
+ stream_url,
129
+ headers=headers,
130
+ allow_redirects=True,
131
+ timeout=60,
132
+ stream=True,
133
+ )
134
+
135
+ print(f"[OKMusic] CDN статус: {response.status_code}")
136
+
137
+ if response.status_code not in (200, 206):
138
+ print("Заголовки:", dict(response.headers))
139
+ return False
140
+
141
+ with open(output_filename, "wb") as f:
142
+ for chunk in response.iter_content(chunk_size=65536):
143
+ if chunk:
144
+ f.write(chunk)
145
+
146
+ print(f"[OKMusic] Сохранено → {output_filename}")
147
+ return True
148
+
149
+ except Exception as e:
150
+ print(f"[OKMusic] Ошибка скачивания: {e}")
151
+ return False
152
+
153
+ def search(self, query: str) -> Dict[str, Any]:
154
+ url = f"{self.base_url}/queryMixedSuggestions;jsessionid={self.jsessionid}"
155
+ params = {"q": query, "client": "web", "locale": "ru"}
156
+
157
+ headers = {
158
+ **self.common_headers,
159
+ "Accept": "application/json, text/javascript, */*; q=0.01",
160
+ "Referer": "https://ok.ru/",
161
+ "X-Requested-With": "XMLHttpRequest",
162
+ }
163
+
164
+ try:
165
+ response = self.session.get(url, params=params, headers=headers, timeout=15)
166
+ response.raise_for_status()
167
+ return response.json()
168
+ except Exception as e:
169
+ print(f"[OKMusic] Ошибка поиска: {e}")
170
+ return {}
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: okmusic-api
3
+ Version: 0.1.0
4
+ Summary: Неофициальный бронированный SDK для работы с музыкальным API Одноклассников (WMF) через jsessionid
5
+ Author-email: l0v3m0n3y <ffxckemweball@gmail.com>
6
+ Project-URL: Homepage, https://github.com/l0v3m0n3y/OkMusic
7
+ Project-URL: Bug Tracker, https://github.com/l0v3m0n3y/OkMusic/issues
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Multimedia :: Sound/Audio
12
+ Requires-Python: >=3.7
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: curl_cffi>=0.7.0
15
+
16
+ # okmusic-api
17
+
18
+ Неофициальный Python SDK для работы со скрытым музыкальным API Одноклассников (WMF).
19
+ Использует `curl_cffi` для идеального обхода TLS-фингерпринтинга (JA3/JA4) распределенной сети CDN Одноклассников.
20
+
21
+ ## Установка
22
+
23
+ ```bash
24
+ pip install okmusic-api
25
+ ```
26
+
27
+ ## Быстрый старт
28
+
29
+ ```python
30
+ from okmusic_api import OKMusicSDK
31
+
32
+ # Твой jsessionid из кук браузера
33
+ sdk = OKMusicSDK(jsessionid="kdCHNeSo76je139vgu...")
34
+
35
+ # Поиск
36
+ results = sdk.search("jesus avgn")
37
+
38
+ # Скачивание трека целиком на диск (без пустых файлов в 0 байт)
39
+ sdk.download_track(123286133220562, "jesus_vssha.mp3")
40
+ ```
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/okmusic_api/__init__.py
4
+ src/okmusic_api/sdk.py
5
+ src/okmusic_api.egg-info/PKG-INFO
6
+ src/okmusic_api.egg-info/SOURCES.txt
7
+ src/okmusic_api.egg-info/dependency_links.txt
8
+ src/okmusic_api.egg-info/requires.txt
9
+ src/okmusic_api.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ curl_cffi>=0.7.0
@@ -0,0 +1 @@
1
+ okmusic_api