Skip to content

Commit ba5d9e6

Browse files
committed
ynison это что то с чем то :) #8 #6 #9 #4
Два дня экспериментов с сокетами, и потоками, а вся вина в одной строке.
1 parent 7b41d63 commit ba5d9e6

2 files changed

Lines changed: 51 additions & 28 deletions

File tree

getToken.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,56 @@
33
from PyQt5.QtCore import QUrl
44
from PyQt5.QtGui import QIcon
55
import sys
6+
import re
7+
8+
URL_WITH_ACCESS_TOKEN_REGEX = r'https:\/\/music\.yandex\.(?:ru|com|by|kz|ua)\/#access_token=([^&]*)'
69

710

811
class CustomWebEnginePage(QWebEnginePage):
12+
def __init__(self, parent=None):
13+
super().__init__(parent)
14+
self.profile().setHttpUserAgent(
15+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36"
16+
)
17+
918
def javaScriptConsoleMessage(self, level, message, lineNumber, sourceId):
1019
pass
1120

1221

1322
class TokenWindow(QMainWindow):
1423
def __init__(self, url, icon_path):
1524
super().__init__()
16-
self.setWindowTitle("Авторизация")
25+
self.setWindowTitle("Authorization")
1726
self.setGeometry(100, 100, 700, 800)
1827
self.setWindowIcon(QIcon(icon_path))
19-
28+
2029
self.browser = QWebEngineView()
2130
self.browser.setPage(CustomWebEnginePage(self.browser))
2231
self.browser.page().profile().cookieStore().deleteAllCookies()
2332
self.browser.urlChanged.connect(self.on_url_changed)
2433

2534
self.browser.setUrl(QUrl(url))
26-
35+
2736
central_widget = QWidget()
2837
layout = QVBoxLayout()
2938
layout.addWidget(self.browser)
3039
central_widget.setLayout(layout)
3140
self.setCentralWidget(central_widget)
32-
41+
3342
self.token = None
3443

3544
def on_url_changed(self, url):
3645
url_str = url.toString()
37-
if "#access_token" in url_str:
38-
self.token = url_str.split("=")[1].split("&")[0]
46+
match = re.search(URL_WITH_ACCESS_TOKEN_REGEX, url_str)
47+
if match:
48+
self.token = match.group(1)
3949
self.close()
4050

4151

4252
def update_token(icon_path):
4353
app = QApplication(sys.argv)
44-
# Official link to OAuth Yandex.Music
45-
oauth_url = "https://oauth.yandex.ru/authorize?response_type=token&client_id=23cabbbdc6cd418abb4b39c32c41195d"
54+
oauth_url = "https://oauth.yandex.ru/authorize?response_type=token&client_id=23cabbbdc6cd418abb4b39c32c41195d" # Official link to OAuth Yandex.Music
4655
token_window = TokenWindow(oauth_url, icon_path)
4756
token_window.show()
4857
app.exec_()
49-
return token_window.token
58+
return token_window.token

main.py

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
CLIENT_ID_RU_DECLINED = "1269826362399522849" # Яндекс Музыку (склонение для активности "Слушает")
4141

4242
# Версия (tag) скрипта для проверки на актуальность через Github Releases
43-
CURRENT_VERSION = "v0.2.3"
43+
CURRENT_VERSION = "v0.3"
4444

4545
# Ссылка на репозиторий
4646
REPO_URL = "https://github.com/FozerG/YandexMusicRPC"
@@ -56,7 +56,8 @@
5656

5757
# --------- Переменные ниже являются временными и не требуют изменения.
5858
# Переменная для хранения предыдущего трека и избежания дублирования обновлений.
59-
name_prev = str()
59+
playable_id_prev = None
60+
info_cache = dict()
6061

6162
# Переменная для хранения полного пути к иконке
6263
icoPath = str()
@@ -106,15 +107,15 @@ def extract_device_name(data):
106107
return f"error: {e}"
107108

108109

109-
async def get_info():
110+
def get_info():
110111
global ya_token
111112

112113
class Info:
113114
def __init__(self, token):
114115
self.token = token
115116

116117
@staticmethod
117-
async def get_track_by_id(track_id):
118+
def get_track_by_id(track_id):
118119
try:
119120
track = Presence.client.tracks([track_id])
120121
if not track or not track[0]:
@@ -208,7 +209,7 @@ async def get_current_track() -> dict:
208209
"app_name": "Chrome",
209210
},
210211
"volume_info": {"volume": 0},
211-
"is_shadow": True,
212+
"is_shadow": False,
212213
},
213214
"is_currently_active": False,
214215
},
@@ -237,7 +238,6 @@ async def get_current_track() -> dict:
237238
track = ynison["player_state"]["player_queue"]["playable_list"][track_index]
238239

239240
await session.close()
240-
track = await (await get_info()).get_track_by_id(track["playable_id"])
241241
return {
242242
"device_name": extract_device_name(ynison),
243243
"paused": ynison["player_state"]["status"]["paused"],
@@ -246,7 +246,7 @@ async def get_current_track() -> dict:
246246
"entity_id": ynison["player_state"]["player_queue"]["entity_id"],
247247
"repeat_mode": ynison["player_state"]["player_queue"]["options"]["repeat_mode"],
248248
"entity_type": ynison["player_state"]["player_queue"]["entity_type"],
249-
"track": track,
249+
"playable_id": track["playable_id"],
250250
"success": True,
251251
}
252252

@@ -326,8 +326,8 @@ def need_restart() -> None:
326326
@staticmethod
327327
def restart() -> None:
328328
Presence.currentTrack = None
329-
global name_prev
330-
name_prev = None
329+
global playable_id_prev
330+
playable_id_prev = None
331331
if Presence.rpc:
332332
Presence.rpc.close()
333333
Presence.rpc = None
@@ -338,16 +338,16 @@ def restart() -> None:
338338
def discord_was_closed() -> None:
339339
log("Discord was closed. Waiting for restart...", LogType.Error)
340340
Presence.currentTrack = None
341-
global name_prev
342-
name_prev = None
341+
global playable_id_prev
342+
playable_id_prev = None
343343
Presence.discord_available()
344344

345345
@staticmethod
346346
def FullClearRPC() -> None:
347347
log("Clear RPC due to error", LogType.Error)
348348
Presence.currentTrack = None
349-
global name_prev
350-
name_prev = None
349+
global playable_id_prev
350+
playable_id_prev = None
351351
Presence.rpc.clear()
352352

353353
# Метод для запуска Rich Presence.
@@ -480,15 +480,30 @@ def update_presence(ongoing_track, current_time=0, paused=False):
480480
# Метод для получения информации о текущем треке.
481481
@staticmethod
482482
def getTrack() -> dict:
483+
global playable_id_prev
484+
global info_cache
483485
try:
484486
current_state = asyncio.run(get_current_track())
485-
if not current_state["success"] or not current_state["track"]["success"]:
486-
log("Not successfully get all the information about the track.", LogType.Error)
487+
if not (current_state and isinstance(current_state, dict) and current_state.get('success') is True):
488+
log("Failed to receive data from ynison.", LogType.Error)
487489
return {"success": False}
488-
track_info = current_state["track"]
490+
491+
current_playable_id = current_state["playable_id"]
492+
isNewTrack = playable_id_prev != current_playable_id
493+
494+
if isNewTrack:
495+
track_info = get_info().get_track_by_id(current_state["playable_id"])
496+
else:
497+
track_info = info_cache
498+
499+
if not (track_info and isinstance(track_info, dict) and track_info.get('success') is True):
500+
log("Failed to get track information.", LogType.Error)
501+
return {"success": False}
502+
503+
playable_id_prev = current_playable_id
504+
info_cache = track_info
489505
name_current = ", ".join(track_info["artists"]) + " - " + track_info["title"]
490-
global name_prev
491-
if str(name_current) != name_prev:
506+
if isNewTrack:
492507
log(f'Now listening to "{name_current}" on device "{current_state["device_name"]}"')
493508
# Если песня уже играет, просто вернем её с актуальным статусом паузы и позиции.
494509
elif Presence.currentTrack["success"]:
@@ -499,7 +514,6 @@ def getTrack() -> dict:
499514
)
500515
return currentTrack_copy
501516

502-
name_prev = str(name_current)
503517
trackId = track_info["track_id"].split(":")
504518
if track_info:
505519
duration_ms = int(current_state["duration_ms"])

0 commit comments

Comments
 (0)