Open Sev73n opened 5 years ago
I try to read BGMMusicPlayer.h to add Netease Music Player support today, but, unfortunately, it does not support the AppleScript interface, like many other players, eg, Clementine(#26).
I wonder can I use other way to support it, like "System Event" of menu bar click or something. But I'm not familiar with Obj-c and Mac app development.
So, I will try, but donโt hold too much hope. : (
I try to read BGMMusicPlayer.h to add Netease Music Player support today, but, unfortunately, it does not support the AppleScript interface, like many other players, eg, Clementine(#26).
I wonder can I use other way to support it, like "System Event" of menu bar click or something. But I'm not familiar with Obj-c and Mac app development.
So, I will try, but donโt hold too much hope. : (
anyway, thank you!
@Sev73n
I learn Objective-C today and finally made a usable version in the night after work, I recorded a video to show it.
If you want to try, you can build it from my fork:
git clone https://github.com/7sDream/BackgroundMusic.git
cd BackgroundMusic
git checkout add_netease_music_support
./build_and_install.sh
Notice: I use AppleScript to operating Netease Music App, which need high permissions, So you need Add Background Music App to the System Preferences -> Security & Privacy -> Privacy -> Accessibility
group, like the following image shows:
Maybe you need restart Background Music.app after add it to the group.
Any feedback is welcome.
To @kyleneideck
The method I used is differ from the codebase, I use NSAppleScript class to exec Apple Script code in the implementation. Now I'm wondering, if I can make a PR like this?
You can see the code I adds from here. I'm a super newbie in Obj-C language and Mac App development, So any suggestion(code, var name, function name, format, etc) are grateful.
Thank your for creating this app, awesome ๐
As I'm writing last comment, I found there is an issue when the frontmost window is in fullscreen mode or Netease Music is in fullscreen mode.
The issue is, in this situation, Netease Music will not respond to the menu click event until I click it's menu bar manually. ๐
So I change to another way, use the Dock icon menu, and it works in fullscreen mode after my test.(But the menu UI will appear, a little annoying)
So, This is the new video for @Sev73n
And code diff for @kyleneideck .
But the code is still tricky, I would build and use it in my own Mac if this can't be merge, which is reasonable. So, It's up to you~
๐บ ๐
Thanks for looking into this, @7sDream. I think it would be worth using your solution until we find a better way, so feel free to make a PR. We can show a warning dialog when Netease is selected, or something like that, to tell people it's experimental and that it might interrupt them occasionally.
I was trying to get a similar music player called Anghami working a while ago and ran into the same problems. The best solution I found was sending synthetic presses of the play/pause keyboard key using CGEventPost
. It works, but macOS only lets you generate media key presses that go to every process. You can't use CGEventPostToPid
to send the keypress to only one process. So if a different music player takes over the media keys, Background Music would start controlling it instead.
You can use CGEventPostToPid
for normal keys, but the media keys are special NSSystemDefined
keys: https://weblog.rogueamoeba.com/2007/09/29/apple-keyboard-media-key-event-handling/. It's pretty unfortunate because most music players support the media keys, so it would have worked for a lot of music players that don't have APIs. (Although, I think macOS has started requiring apps that generate mouse or keyboard events to be in System Preferences -> Security & Privacy -> Privacy -> Accessibility
.)
I tried it with Netease and it seemed to work fine.
Maybe we could add a generic music player to Background Music that generates media key presses and just explain to the user how it works. Background Music has to be able to figure out whether the music player is running, playing and/or paused, though. That could be tricky.
I've also noticed that macOS handles the media keys a bit differently to the way it handled them when I looked into this before. (Either that or I just missed a big part of the process.) The process rcd
handles keypresses for the play/pause button by using MediaRemote.framework
(private) to send a TogglePlayPause
command to mediaremoted
via XPC.
Then mediaremoted
plays/pauses your Now Playing app, which is the app that's shown under "Now Playing" in the macOS sidebar/notification area. This article has a good explanation: https://paper.tuisec.win/detail/e89f06a55e3dd47.
Some third-party music/media players use the private framework to become the Now Playing app, for example: https://github.com/plexinc/plex-media-player/blob/master/src/input/apple/InputAppleMediaKeys.mm#L134. (See also: https://github.com/WebKit/webkit/blob/bde8ac5bddc49527396f3adb576d9a101a8e4828/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm#L202.)
It looks like Netease does the same, so I've been trying to figure out a way to tell mediaremoted
to play/pause a specific music player. I'm still working on it, though.
@kyleneideck Thanks for your advice and information about MediaKey.
I will try add a warning dialog and make an Pr this weekend if I'm not busy.
The media key solution seems great if we can just make the BGM Player receive the event, I will look into it.
I think I've reverse engineered enough of the MediaRemote message to get play/pause working. Here's a proof-of-concept:
It should play/pause Netease, even when a different app is the Now Playing app and Netease isn't receiving media key presses.
I used XPoCe to log the XPC message sent by rcd
when I press the play/pause key. (I hadn't realised there's an XPoCe version 2.) The message is mostly straightforward, but there are some parts I haven't figured out yet.
It's a dict with four keys: MRXPC_NOWPLAYING_PLAYER_PATH_DATA_KEY
, MRXPC_COMMAND_KEY
, MRXPC_MESSAGE_ID_KEY
and MRXPC_COMMAND_OPTIONS_KEY
. MRXPC_NOWPLAYING_PLAYER_PATH_DATA_KEY
is encoded as a protobuf and MRXPC_COMMAND_OPTIONS_KEY
is encoded as a binary plist. The others are ints.
@7sDream Could you try the proof-of-concept and see if it works for you? If it does, maybe you could use it in your PR. (Sorry the code is such a mess.)
I'm still working on figuring out how to tell whether Netease is playing, paused or stopped.
https://itunes.apple.com/cn/app/%E7%BD%91%E6%98%93%E4%BA%91%E9%9F%B3%E4%B9%90/id944848654?mt=12
Netease Cloud Music is the most popular music player in china,
please add it to your list
thank you !