Skip to content

Commit

Permalink
Add time out after 30min, disconnect RPC
Browse files Browse the repository at this point in the history
Removed requirement for admin
Refactored out disconnect_discord
Reset GUI song info if NCM is not found
Improve robustness by moving check for connection right before RPC update attempt
  • Loading branch information
aliencaocao committed Aug 17, 2024
1 parent 5d2ee86 commit cc0e364
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 21 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ Written in pure Python, supports latest versions of NetEase Cloud Music. Current

使用X关闭程序窗口后,程序会以托盘图标的形式在后台继续运行。右键托盘图标可以控制程序。

程序必须以管理员运行才能正常工作。请右键exe文件,点击以管理员身份运行
如果网易云音乐是以管理员运行的,则该程序也必须以管理员运行才能正常工作。否则,该程序不需要管理员权限

与BetterDiscord等第三方Discord客户端不兼容。

Download the executable binary (exe) from the Release page, Keep the exe running.

If you close the program window with X, the program will continue to run in the background as a tray icon. Right-click the tray icon to control the program.

The program requires administrator permission to work properly. Please right-click on the exe, and click run as administrator.
If you run NCM as admin, then the program will also require admin permission to work. Otherwise, no admin permission is required.

Not compatible with third-party Discord clients such as BetterDiscord.

Expand Down
66 changes: 48 additions & 18 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ def connect_discord(presence: Presence) -> bool:
return True


def disconnect_discord(presence: Presence):
try:
presence.clear()
presence.close()
except Exception as e:
logger.warning(f'Error while disconnecting Discord:', e)
connected_var.set(False) # set to false anyways because the only reason why it could fail is due to already disconnected/already closed async loop, which means it is disconnected already
return False
else:
logger.info(f'Disconnected from Discord.')
connected_var.set(False)
return True


client_id = '1045242932128645180'
RPC = Presence(client_id)

Expand All @@ -147,6 +161,8 @@ def connect_discord(presence: Presence) -> bool:
last_status = Status.changed
last_id = ''
last_float = 0.0
last_pause_time = time.time()
pause_timeout = 30 * 60
stop_variable = ThreadingEvent()

song_info_cache: Dict[str, SongInfo] = {}
Expand Down Expand Up @@ -291,34 +307,27 @@ def update():
global last_status
global last_id
global last_float
global last_pause_time

try:
if not pid_exists(pid) or get_process_name(pid) != 'cloudmusic.exe':
pid, version = find_process()
if not pid: # If netease client isn't running, clear presence
logger.warning('Netease Cloud Music not found. Disconnecting RPC.')
logger.warning('Netease Cloud Music not found.')
song_title_text.set('N/A')
song_artist_text.set('')
if not first_run:
RPC.clear()
RPC.close()
connected_var.set(False)
disconnect_discord(RPC)
first_run = True
return

if version not in offsets:
stop_variable.set()
raise UnsupportedVersionError(f"This version is not supported yet: {version}.\nSupported version: {', '.join(offsets.keys())}" if not is_CN else f"目前不支持此网易云音乐版本: {version}\n支持的版本: {', '.join(offsets.keys())}")

if first_run:
logger.info(f'Found process: {pid}')
first_run = False

if not connected_var.get():
if connect_discord(RPC):
connected_var.set(True)
else:
logger.error('Failed to connect to Discord.')
return

process = open_process(pid)
module_base = get_module(process, 'cloudmusic.dll')['base']

Expand All @@ -340,24 +349,43 @@ def update():
# Song ID is not ready yet.
return

# Interval should fall in (interval - 0.2, interval + 0.2)
status = (Status.playing if song_id == last_id and abs(current_float - last_float - interval) < 0.1
# Measured interval should fall in (interval +- 0.2)
status = (Status.playing if song_id == last_id and abs(current_float - last_float - interval) < 0.2
else Status.paused if song_id == last_id and current_float == last_float
else Status.changed)

if status == Status.playing:
if last_status != Status.paused: # Nothing changed
last_float = current_float
last_status = Status.playing
return
elif last_status == Status.paused: # we resumed from pause and may need to reconnect if passed time out
logger.debug('Resumed')
if not connected_var.get():
if not connect_discord(RPC):
return

elif status == Status.paused:
if last_status == Status.paused: # Nothing changed
if last_status == Status.paused: # Nothing changed but check if it is idle/paused for more than 30min, disconnect RPC until resumed to playing.
if connected_var.get() and time.time() - last_pause_time > pause_timeout:
logger.debug('Idle for more than 30min, disconnecting RPC.')
disconnect_discord(RPC)
return
else:
elif last_status == Status.playing:
logger.debug('Paused')
last_pause_time = time.time()

elif status == Status.changed:
last_pause_time = time.time() # reset timeout as changed indicates something happened
if not connected_var.get():
if not connect_discord(RPC):
return

song_info = get_song_info(song_id)

if not (connected_var.get() or not time.time() - last_pause_time > pause_timeout):
if not connect_discord(RPC):
return

try:
RPC.update(pid=pid,
state=f"{song_info['artist']} | {song_info['album']}",
Expand All @@ -368,6 +396,7 @@ def update():
small_text='Playing' if status != Status.paused else 'Paused',
start=int(time.time() - current_float)
if status != Status.paused else None,
# Known issue: buttons do not appear on PC due to discord API changes: https://github.com/qwertyquerty/pypresence/issues/237
buttons=[{'label': 'Listen on NetEase',
'url': f'https://music.163.com/#/song?id={song_id}'}]
)
Expand All @@ -386,7 +415,8 @@ def update():

last_id = song_id
last_float = current_float
last_status = status
if status != Status.changed: # only store play/pause status for ease of detection above
last_status = status

if status != Status.paused:
logger.debug(f"{song_info['title']} - {song_info['artist']}, {current_pystr}")
Expand Down
2 changes: 1 addition & 1 deletion src/main.spec
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ exe = EXE(
codesign_identity=None,
entitlements_file=None,
version='version.txt',
uac_admin=True,
uac_admin=False,
uac_uiaccess=False,
icon=['app_logo.ico'],
)

0 comments on commit cc0e364

Please sign in to comment.