i8beef / node-red-contrib-castv2

MIT License
22 stars 14 forks source link

Add Spotify Support #22

Closed ChillXXL closed 3 years ago

ChillXXL commented 4 years ago

I found problems with some commands and cannot figure out why. The command "GET_CAST_STATUS" works, see below, but if I changed the command to "PAUSE" or "PLAY" it doesn't work and get the "Error: Malformed command" while playing Spotify.

{working node red function node} return { host: "192.168.2.8", // optional if specified on the node itself port: 8009, // optional, defaults to 8009 appId: "CC32E753", // optional, allows launching and controlling apps other than DefaultMediaReceiver, payload: { type: "GET_CAST_STATUS", } }; <<<

{NOT working node red function node} return { host: "192.168.2.8", // optional if specified on the node itself port: 8009, // optional, defaults to 8009 appId: "CC32E753", // optional, allows launching and controlling apps other than DefaultMediaReceiver, payload: { type: "PAUSE", } }; <<<

What am I doing wrong? I trying to get play/pause and next/previous control of the chromecast. Can you help me?

i8beef commented 4 years ago

Media control commands are only supported on the DefaultMediaReceiver app. CC32E753 appears to be the Spotify app. Every app can implement its own command structures, etc., so every individual app would need to be supported individually which is obviously out of scope. The AppId here can really only be used to LAUNCH an application, but not control arbitrary command structures.

ChillXXL commented 4 years ago

Hello i8beef,

Thanks for your fast reply. I tried every possible option, now I know it won't work to control Spotify. I understand that it is out of scope for your project. Thanks anyhow.

I will figure out another way. So far I noticed that a Python script called 'PyChromecast' can controll the chromecast with multiple apps like Spotify. Now a way to implement it in Node Red :-)

i8beef commented 4 years ago

While media commands are supposed to be relatively common, the underlying app launch / media load logic can vary wildly for every app. That makes it really hard to support ARBITRARY apps, and would require specific nodes per supported APPID basically. That is, while it could theoretically JOIN an existing session, LAUNCHING a new session of any arbitrary app could be problematic.

That is not to say that this module COULDN'T expose a couple of nodes for some common Cast apps. Off the top of my head, YouTube (not hard), Netflix and other video streaming apps (tough), Plex (some examples), Spotify (having trouble finding examples), Google Music (no examples).

If I undertook that though, I'd basically be rewriting this entire node in order to change the architecture to support shared connections to the cast targets (i.e., maintain a connection to the configured Chromecast 24/7 when node is running, ala the MQTT node, etc.), and genericizing the launch / control capabilities across multiple nodes (one per supported app).

Im not saying I won't do it, in fact I've considered it, tried, and failed / got bored once or twice already... but that is a pretty hefty overhaul.

ChillXXL commented 4 years ago

It took me quite some time to connect all the dots (I am no programmer) but I have got it working; I can control Spotify on my chromecast. (Play, Pause, previous Track, Next Track)

I must say it was quite a investigation to figure it out all the relations and must say I must it still redirects quite a lot between different java-scripts which propably can be improved.

FROM Node-Red: castv2-sender.js to spotify.js ( newly created by myself and part of castv2-client") TO media.js (part of "castv2-client") TO Chromecast

What I did (FYI):

"castv2-client"

  1. GO TO node folder "castv2-client" <PART 1>
  2. Folder 'lib/senders'
  3. Make a copy of 'default-media-receiver' to 'spotify.js'
  4. Modify 'spotify.js' with the spotify.APP_ID = 'CC32E753' and optional rename 'DefaultMediaReceiver' renames in the script to 'Spotify'
  5. Add extra controls like 'queue_next' to control next track (optional)
  6. GO TO last line and chang module.exports = Spotify <PART 2>
  7. Folder 'lib/controllers'
  8. Modify media.js
  9. Add extra controls for next track and previous track if needed (optional) <PART 3>
  10. GO TO index.js and add module .exports.Spotify = require('./lib/senders/spotify')

castv2-sender.js

  1. change line 5; ...require("castv2-client").DefaultMediaReceiver to ...require("castv2-client").Spotify
  2. Add extra lines (~row 44) in the media command handler for next and previous track (optional)
  3. Add extra cases (~row 120) in the media command switch for next and previous track (optional)

Reboot Node Red.

To do: by next or previous track the status of node stays on "sending" (yellow) instead of returning to idle (green). If you have any hints tot solve this that would be great.

Maybe this can help you the possibility for adding control of other apps on the chromecast. And feel free to give me feedback If I could have things different/better :-)

Inspired by: Youtube added control AND PyChromecast

i8beef commented 4 years ago

So I just rearchitected for 3.0.0... Adding Spotify, or any other application should now be possible in theory. If you're up for it, I'd take a pull request for it... You would just need to make a lib/SpotifyReceiverAdapter, lib/SpotifyReceiver, and possibly a lib/SpotifyController if there are Spotify specific pieces that are needed (i.e., the extra next/previous track parts that are possibly their own cast namespace?), and then add the necessary parts to castv2-sender.js to allow them to be used (just look for "YouTube" and add similar lines for Spotify.

I wanna say there were Spotify authentication pieces from some example I saw, and if that's the case it might be a tiny bit more involved, but I passed in the parent node in initReceiver in the Adapters specifically to allow pulling "config" information like authentication user / pass...

i8beef commented 4 years ago

I added preliminary Spotify architecture pieces... It is not fully implemented, and is largely derived from some of the chromecast python code examples so it still needs dragged over the line. It might connect to existing sessions and control (not play new though) as is...

i8beef commented 4 years ago

Adding "Help Wanted" as I don't actually have a Spotify account to work with here. The architecture pieces are pretty much in place, but the actual implementation still needs worked out for the following:

  1. Proper authentication to the API, right now its just hard coded to take a prefetched token, which once expired, will just be useless again.
  2. "load" needs actually implemented / tested. It's a no-op right now, as I couldn't find a lot of examples of how to actually start something playing... If the underlying mediaController is actually supported by Spotify's app, then it should just accept a properly formatted message and pass it on, otherwise, evidence points to having to call the Spotify API with a known device id to begin something playing.
  3. And additional features like "next"/"previous" tracks, would probably need to be added at some point.
  4. MEDIA_STATE should publish when the cast app is playing stuff, etc... but its unclear if that will actually have all the right information in it, or if the Spotify app even publishes this (I imagine it would as its kind of a "standard" for media control...). Just be nice to know this is working.

If someone wants this working and is feeling adventurous, here's a few possible other code bases to reference, though it doesn't really look like many of them are complete...

  1. https://github.com/openhab/openhab-addons/tree/2.5.x/bundles/org.openhab.binding.spotify
  2. https://github.com/home-assistant-libs/pychromecast/blob/master/pychromecast/controllers/spotify.py
  3. https://developer.aliyun.com/mirror/npm/package/castv2-client - Repo is gone, but this mirror supplies tarballs, definitely not complete, and roughly where I'm leaving this implementation in terms of "doneness".
tjc998 commented 3 years ago

Having a quick look at this. The actual Spotify developer site has some good examples of how to implement #1 and maybe #2 still looking. I have a premium account so I can test as i go.

ChillXXL commented 3 years ago

Hello again,

I just dl your latest release and test the QUEUE_NEXT and QUEUE_PREV while playing spotify and worked great. Thx!