Hammerspoon / hammerspoon

Staggeringly powerful macOS desktop automation with Lua
http://www.hammerspoon.org
MIT License
12.09k stars 582 forks source link

Spotify - save a song to the user's library #2010

Open fharper opened 5 years ago

fharper commented 5 years ago

It would be nice to add the save tracks feature to the Spotify available functions.

latenitefilms commented 5 years ago

Whilst certainly possible, the links you point to are referring the Web API, as opposed to the AppleScript API which the hs.spotify extension is currently using.

In the meantime, you could simply use hs.execute (or hs.task) to do something like this:

hs.execute([[curl -i -X PUT "https://api.spotify.com/v1/me/tracks" -H "Authorization: Bearer {your access token}" -H "Content-Type: application/json" --data "{ids:[\"4iV5W9uYEdYUVa79Axb7Rh\", \"1301WleyT98MSxVHPZCA6M\"]}"]]
fharper commented 5 years ago

Thanks @latenitefilms

drn commented 4 years ago

I realize that this thread is over year old, but in case this is helpful -

Unfortunately, the Spotify osascript interface doesn't have access to this. I wanted a hotkey for this myself, so I spent a weekend solving this through a CLI-integration that handles OAuth integration / refreshing of auth tokens / lookup of current song with the Spotify API - all hooked up to a Hammerspoon hotkey.

Here is the golang CLI I wrote that does this:

Hammerspoon integration:

I haven't yet extracted this out of my dotfiles into a standalone CLI. If there is interest, just let me know and I can make it available

latenitefilms commented 4 years ago

I reckon you could probably archive the same thing you've done in Go with Lua in Hammerspoon?

drn commented 4 years ago

Yes, definitely feasible.

If anyone is interested in writing the Lua logic into Hammerspoon - the complexity lies in the user needing to set up a Spotify developer OAuth application & needs to follow the OAuth authorization code callback flow to exchange a code for an access token and a refresh token. After that, tokens can be refreshed automatically using a cached refresh token. I handled it with CLI prompts and by adding a callback endpoint to my homepage, but I'm sure there are cleaner ways of doing this — like setting up a local server and capturing the callback data directly like the Github CLI does.

manojkarthick commented 2 years ago

I'm just starting to explore Hammerspoon and was also looking to save/remove the currently playing song.

After some digging, I found that the keyboard shortcut to save/remote the currently playing song to the library is Option+Shift+B. I haven't used AppleScript, but would this be easier to add to the Spotify extension compared to using the Web API?

drn commented 2 years ago

@manojkarthick — thanks for flagging that! Here's some AppleScript that does exactly that:

activate application "Spotify"
tell application "System Events"
  keystroke "b" using {option down, shift down}
end tell

Unfortunately, this requires that the application must be activated (in the forefront). So, hooking this up to a hotkey would result in the Spotify application coming to the forefront every time it's pressed. I don't know of a way to send hotkeys to an application without activating it first if the application doesn't expose that functionality in its AppleScript library. If anyone knows how to do that, then please let me know!

The simplest thing would be for Spotify to expose the Like / Unlike as part of its AppleScript library, but alas — that's not in my control.

Separately, I found an easier way to go about this. You can install spotify-tui and hook into the commands spt playback --like and spt playback --dislike commands triggered by a HS binding via os.execute(...). It still requires hooking into the Spotify API and authorizing an OAuth application, but the CLI looks to be well maintained.

manojkarthick commented 2 years ago

Having to activate the application definitely makes the shortcut not as useful.

Thanks a lot for the tip regarding spotify-tui @drn - this is awesome! I just tried it using my developer account and it seems to be pretty seamless.

latenitefilms commented 2 years ago

In THEORY, you should be able to use hs.eventtap.keyStroke(modifiers, character[, delay, application]) to send a keystroke to a specific application, even if it's not the active application.

drn commented 2 years ago

Holy shit @latenitefilms @manojkarthick — that worked! This is why I love Hammerspooon.

  local app = hs.application.find("com.spotify.client")
  hs.eventtap.keyStroke({"option", "shift"}, "b", app)

It looks like we can't explicitly trigger a "like" or "dislike", but this for sure solves the toggling use-case.

manojkarthick commented 2 years ago

Amazing 💯 - Thanks @drn @latenitefilms!