Skip to content

Latest commit

 

History

History
179 lines (155 loc) · 6.42 KB

README.org

File metadata and controls

179 lines (155 loc) · 6.42 KB

What is it.

emms-player-spotify is a EMMS player implementation which delegates to an open desktop Spotify app. It support playing URLs in Spotify’s default “share” format, e.g. https://open.spotify.com/album/5l5m1hnH4punS1GQXgEi3T. Internally these urls are converted to shorter spotify:<type>:<id> URIs, in the same format as returned by Spotify’s API.

Features:

  • player’s state is synchronised between EMMS and Spotify
    • manual seeking in spotify is recognized by EMMS
    • play/pause works in both directions
  • supports muting ads
  • emms-player-spotify-following minor mode to keep history of played tracks
  • integrated with EMMS modeline module

Installation

EMMS

If you haven’t used it yet, then here is a minimal config.

(use-package emms
  :config
  (emms-all)
  (emms-default-players)
  (emms-history-load))

emms-player-spotify

(use-package emms-player-spotify
  :straight (emms-player-spotify :type git :host github :repo "sarg/emms-spotify")

  :custom
  (emms-player-spotify-launch-cmd "flatpak run com.spotify.Client")
  (emms-player-spotify-adblock t)

  :config
  (add-to-list 'emms-player-list emms-player-spotify))

Install Spotify from FlatHub. In the app settings disable Autoplay.

Usage

Playing individual tracks

Tracks can be added one by one using M-x emms-add-url followed by a open.spotify.com link. Here are example track links you can use for a test.

https://open.spotify.com/track/6ZsZxNP4Iwdyp3kd5oFFQN
https://open.spotify.com/track/5aVJ5rv7ghWSkQaqP726tE
https://open.spotify.com/track/0Klbxk3g96Qae4DbCnUNcT
https://open.spotify.com/track/4KVTRIZIj1WWIxitbREDnK
https://open.spotify.com/track/55mJleti2WfWEFNFcBduhc
https://open.spotify.com/track/3EeoMkZF8NhX9FdCSxG8MB
https://open.spotify.com/track/1vxu8vMNshg5J8z3oA7QJZ
https://open.spotify.com/track/0Cnx6PGogxIE2RnDcnoeK8
https://open.spotify.com/track/7tvuLLroI0n6uYBWuFig5d
https://open.spotify.com/track/1FRlNrHd4OGNIEVgFuX9Fu
https://open.spotify.com/track/0R7HFX1LW3E0ZR5BnAJLHz
https://open.spotify.com/track/2D9rd6TIpqmDkog5Mx8kxl
https://open.spotify.com/track/3oEgMtjTzGgXTFdO0IW2M7

You can also save these links to a .m3u file and open it using M-x emms-add-m3u-playlist.

Following mode

This mode is much easier to use, just add any Spotify “collection” URL, e.g. an album or a playlist, and this collection will be expanded to individual tracks as you listen to them. You won’t be able to see the next tracks though, only the past ones.

Try it with M-x emms-add-url RET <link>. E.g. TOOL - Lateralus.

Once the queue ends, the resulting playlist could be saved locally with C-x C-s.

counsel-spotify integration

counsel-spotify provides dynamic search functions for spotify content. Here is an example setup that will expand albums into individual tracks. For other non-track playables (playlist or artist) it will popuplate the title.

(use-package counsel-spotify
  :defer t
  :custom
  (counsel-spotify-use-notifications nil) ; conflicts with handlers of emms-player-spotify
  ; (counsel-spotify-client-id "my-client-id")     ; you can hardcode the credentials
  ; (counsel-spotify-client-id "my-client-secret") ; in case your config is strictly private

  :config
  ; load secrets from auth-source-pass on first call
  (if (string-empty-p counsel-spotify-client-secret)
      (setq counsel-spotify-client-id (auth-source-pass-get "client-id" "Sites/spotify.com")
            counsel-spotify-client-secret (auth-source-pass-get "client-secret" "Sites/spotify.com")))

  (defun emms-player-spotify-expand-album (id)
    (counsel-spotify-with-auth-token (auth-token)
     (counsel-spotify-with-query-results
      (auth-token (concat counsel-spotify-spotify-api-url "/albums/" id "/tracks") results)

      (with-current-emms-playlist
        (goto-char (point-max))
        (ignore (mapc (lambda (el)
            (let ((track (emms-track 'url (uri el))))
              (emms-track-set track 'info-title (name el))
              (emms-track-set track 'info-artist (name (artist el)))
              (emms-track-set track 'info-album (name (album el)))
              (emms-track-set track 'info-playing-time (round (* 1e-6 (duration-in-ms el))))
              (emms-playlist-insert-track track)))
          (counsel-spotify-parse-items (list (cons 'tracks results)) 'tracks)))))))

  (cl-defmethod counsel-spotify-do-play ((backend counsel-spotify-linux-backend) (playable counsel-spotify-playable))
    (with-current-emms-playlist
      (goto-char (point-max))
      (cond
       ((counsel-spotify-album-p playable)
        (emms-player-spotify-expand-album
         (nth 2 (string-split (uri playable) ":"))))

       (t
        (let ((track (emms-track 'url (uri playable))))
          (emms-track-set track 'info-artist "Spotify Playlist")
          (emms-track-set track 'info-title
                          (decode-coding-string (string-make-unibyte (name playable)) 'utf-8))
          (emms-playlist-insert-track track)
          (emms-playlist-mode-play-current-track)))))))

Timelines

p - paused
> - playing
□ - stopped
m - mute
u - unmute
a - ad
[ - add temporary ad track
] - remove temporary track
+ - add track in following mode

EMMS controls

EMMS  >     p     >    □
------+-+---+-+---+-+--+-+--->
SPOT    >     p     >    p

Spotify controls

EMMS  >      p    >
------+-+--+-+--+-+--->
SPOT    >  p    >

Ads in track-by-track mode

EMMS  >     [m   m   up] >
------+-+-+-+--+-+-+-+---+-+->
SPOT    > a    a   p       >

Following mode

EMMS  >   +>   +>
------+-+-+--+-+--->
SPOT    >    >

Ads while following

EMMS  >     [m   m   u]+>
------+-+-+-+--+-+-+-+------>
SPOT    > a    a   >

TODOs [2/6]

  • [X] expand spotify:album: to a playlist
  • [ ] expand spotify:playlist:
  • [ ] better support for playlists
  • [ ] implement emms-info-function to retrieve dynamic playlist names
  • [ ] try “seeded” playlists Recommendations API
  • [X] implement seek
  • drag-n-drop to emms
  • playback to chromecast