Git Product home page Git Product logo

polybar-spotify-module's Introduction

Polybar Spotify Module

polybar-spotify-module

This is a pure C implementation of an external polybar module that signals polybar when a track is playing/paused and when the track changes. There is also a program that retreives the title and artist of the currently playing song on spotify.

Requirements

DBus is used for listening to spotify track changes. Obviously you need spotify and polybar as well: dbus polybar spotify

To compile the program, you will need make.

You most likely already have the above packages installed. Systemd depends on DBus, and you wouldn't be looking at this, if you didn't have polybar and spotify installed.

How to Setup

Installing the Program

Run the following code to clone the repo and install the programs.

git clone https://github.com/mihirlad55/polybar-spotify-module
cd polybar-spotify-module/src/
sudo make install

Arch Linux Users

polybar-spotify-module exists as a package on the AUR! Use your favourite AUR helper to install the package.

yay -S polybar-spotify-module

The package can be found here https://aur.archlinux.org/packages/polybar-spotify-module/.

Running spotify-listener in the Background

spotify-listener must run in the background for it to be able to listen for track changes and communicate with polybar. There are two ways to keep it running in the background. If you are using systemd, you can have it start at system startup by running:

systemctl --user enable spotify-listener

Then, you can start the service now by running:

systemctl --user start spotify-listener

If you are not using systemd, make sure the spotify-listener program is executed at startup. Something like

spotify-listener &
disown

in a startup script should accomplish that.

Configuring Polybar

Your polybar configuration file should be located at .config/polybar/config

First make sure IPC is enabled. The following should be in your configuration file under the [bar/<your bar name>] section:

[bar/main]
enable-ipc = true

If you plan to use icons for next/play/previous/pause buttons, make sure you add (and have installed) an icon font accordingly such as NerdFonts or FontAwesome under the [bar/<your bar name>] section:

[bar/main]
font-1 = Font Awesome 5 Free:size=10;1

Note that the font is specified in modules as a 1-based index, so font-1 is specified by format-font = 2.

Next, add the following spotify modules:

[module/previous]
type = custom/ipc
format-font = 2
; Default
hook-0 = echo ""
; When spotify active
hook-1 = echo "Previous"
click-left = "spotifyctl -q previous"


[module/next]
type = custom/ipc
format-font = 2
; Default
hook-0 = echo ""
; When spotify active
hook-1 = echo "Next"
click-left = "spotifyctl -q next"


[module/playpause]
type = custom/ipc
format-font = 2
; Default
hook-0 = echo ""
; Playing
hook-1 = echo "Pause"
; Paused
hook-2 = echo "Play"
click-left = "spotifyctl -q playpause"


[module/spotify]
type = custom/ipc
; Default
hook-0 = echo ""
; Playing/paused show song name and artist
hook-1 = spotifyctl -q status --format '%artist%: %title%'

You can replace the text for Pause/Play/Next/Previous with icons for each of the hooks.

Lastly, make sure the new spotify modules are part of your bar. Make sure one of the following lines is part of your modules.

modules-center = spotify previous playpause next
modules-left = spotify previous playpause next
modules-right = spotify previous playpause next

Status Formatting

The spotifyctl status command has multiple formatting options. You can specify the:

  • Maximum output length
  • Maximum artist length
  • Maxiumum track title length
  • Output Format
  • Truncation string

By default, the above lengths are INT_MAX (no limit). Additionally, if max length is specified, the artist and track title will not be truncated if the untruncated output satisfies the output max length constraint.

The tokens %artist% and %title% can be used to specify the output format.

For example for the artist Eminem and track title Sing For The Moment

spotifyctl status --format '%artist%: %title%' --max-length 20 \
    --max-title-length 10 --max-artist-length 10 --trunc '...'

would result in the following output

Eminem: Sing Fo...

For more information and examples, you can run the command spotifyctl help.

How it Works

The spotify-listener program connects to the DBus Session Bus and listens for two particular signals:

  • org.freedesktop.DBus.ProprtyChanged for track changes
  • org.freedesktop.DBus.NameOwnerChanged for spotify disconnections

Using this information, it sends messages to spotify polybar custom/IPC modules to show/hide spotify controls and display the play/pause icon based on whether a song is playing/paused.

The spotifyctl program calls org.mpris.MediaPlayer2.Properties.Get method to retreive status information and calls methods in the org.mpris.MediaPlayer2.Player interface to pause/play and go to the previous/next track.

Why Did I Make this in C

  • Practice/learn low-level C
  • Reduce number of dependencies
  • Make something as lightweight as possible by directly interfacing with DBus
  • For fun 😜

Resources

The following are very useful resources for DBus API and specs:

Credits

Inspired by the python implementation by dietervanhoof: https://github.com/dietervanhoof/polybar-spotify-controls

polybar-spotify-module's People

Contributors

fryday avatar mihirlad55 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

polybar-spotify-module's Issues

make: pkg-config: No such file or directory

I followed all of the instructions, but after running sudo make install I get this:

$ sudo make install
Password:
make: pkg-config: No such file or directory
mkdir -p ../obj
gcc -c -o ../obj/utils.o utils.c  -ldbus-1
In file included from utils.c:1:
../include/utils.h:4:10: fatal error: dbus-1.0/dbus/dbus.h: No such file or directory
    4 | #include <dbus-1.0/dbus/dbus.h>
      |          ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:73: ../obj/utils.o] Error 1

‘for’ loop initial declarations are only allowed in C99 mode

Hi,

I am not a dev, I have no experience with C and compiler, nor have any clue as to why my compiler would compile with such an old version of C.

I also have no clue on how to specify on the Makefile that I want the following flag : -std=c99.

However I made 3 changes to the C files and got it to work.

spotifyctl.c line 336 :
int i = 1; // Parse commandline options for (i = 1; i < argc; i++) {

spotify-listener.c line 131 :
int p = 0; for (p = 0; p < num_of_paths; p++) {

spotify-listener.c line 136 :
int m = 0; va_start(args, numOfMsgs); for (m = 0; m < numOfMsgs; m++) {

Declaring the variable outside the for loop fixed the issues. type_t would not be understood by my compiler hence I changed those to int. Once done I could compile just fine.

gcc --version gcc (GCC) 7.3.0 make --version GNU Make 3.82 OS : CentOS 7

2 Questions Actually, (Spotifyd support any updates + displaying album names along side artist & track)

The first part is just a check in on if any progress has been made with perhaps getting the plugin to natively work with Spotifyd reliably, I'd love to hear if any progress has been made,

The second question is more of a formatting addition, i noticed that there is native support for pulling artist's names %artist% and track names %title%. but not for pulling album names at least from what i can see in the documentation. out of curiousity i tried %album% to no avail.

Perhaps a near future addition? I love this module so much, and i look forward to it inevitalby being compatible with Spotifyd + Spotify TUI as ive grown preferable to using that over the official client.

Great work and I hope to hear back soon

Package dbus-1 was not found in the pkg-config search path.

Followed the instructions, but if I run: sudo make install it will show:
Package dbus-1 was not found in the pkg-config search path.
Perhaps you should add the directory containing 'dbus-1.pc' to the PKG_CONFIG_PATH environment variable
No package 'dbus-1' found
mkdir -p ../obj
gcc -c -o ../obj/utils.o utils.c -ldbus-1
In file included from utils.c:1:
../include/utils.h:4:10: fatal error: dbus-1.0/dbus/dbus.h: No such file or directory
4 | #include <dbus-1.0/dbus/dbus.h>
| ^~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:73: ../obj/utils.o] Error 1

Spotifyd support

The program mostly works out of the box with spotifyd. Only a few additional code changes are required to support spotifyd.

The main problem with full spotifyd support is spotifyd's PropertiesChanged event does not always fire which causes the polybar modules to fail to update. This isn't a problem with polybar-spotify-module, but a problem with spotifyd itself

See the following links. It looks like the issue is actively being worked on:

This steals the focus on i3

Im loving this script, but now when i open a window next to spotify on i3, spotify gets the focus again. How can i fix it?

Find polybar IPC files

Polybar IPC files are currently hardcoded. Add function to automatically find polybar IPC files. This probably needs to be done every message write since the bar may have been restarted during the script execution resulting in new/different IPC files.

Truncating non-ascii characters displays unprintable characters causing polybar to freak out.

As the title says, long non-english song titles sometimes have this bug when truncated.

Polybar log error:

polybar|warn:  Dropping unmatched character  (U+0011) in '  Твин Пикс - По шанхай�.'

The bar gets completely blanked out and blurred by my compositer (picom). And if I kill picom it will just be a blank black line.

Also I have noticed that some non-english titles get truncated as normal but some cause this. The non-english titles that broke it with me is Russian and Arabic characters.

Steps to reproduce:

  • Polybar module:
[module/spotify]
type = custom/ipc
; Default
hook-0 = echo ""
; Playing/paused show song name and artist
hook-1 = spotifyctl -q status --format '%artist% - %title%' --max-length 50 --max-title-length 20 --max-artist-length 20 --trunc '..'
  • Song with title that includes "bad" characters:

https://open.spotify.com/track/26HmgTNZiSyTtK8iWw8cxv?si=b0da790af46e445d

Also here is an example of a song witch Russian characters that gets truncated normally:

https://open.spotify.com/track/5Qbmmuhe3kvAFZ4Oe6kfmP?si=f38ba013e05a499f

I have tried to fix by messing with truncating function in utils.c but I couldn't figure it out.

Not working since last Spotify update

In the last Spotify update on my machine, running Manjaro, this stopped working.
Here are the relevant portions of my config file:

[module/playpause]
type = custom/ipc
format-font = 2
format-underline = #1db954
format-background = ${color.shade2}
; Default
hook-0 = echo "  No Song is Playing"
; Playing
hook-1 = echo ""
; Paused
hook-2 = echo ""
click-left = "spotifyctl -q playpause"


[module/spotify]
type = custom/ipc
format-underline = #1db954
format-background = ${color.shade2}
; Default
hook-0 = echo ""
; Playing/paused
hook-1 = spotifyctl -q status

And enable-ipc is set to true.

If I use custom/script instead of custom/ipc and use exec instead of hook-1, then everything works as expected, it just takes a while to update the bar.
Any idea on why this is happening?

Here's the full config file if relevant:
config.txt

Does this work if spotify is installed by snap?

Im on arch-linux and for some reason whenever I download spotify from aur it crashes at launch. I can only open it if its downloaded with snap. So will this module work if spotify is installed by snap?

Add maximum width for the output

Hi and thanks for this nice module! I've got a problem, however. Long song titles will push other modules out of the screen which could be stopped by adding a maximum width where the output is cut or alternatively starts to scroll.

Issue with Song Title not Changing when Switching Song

I am sure there is a simple fix - my issue is that upon switching song, the text doesn't alter; in order for the text to be updates I have to restart the spotify-listener serveice, but then run into the same issue upon song switch.

Any help would be great appreciated, great module!

spotify-listener bug [Arch]

Versions

os: arch
polybar-spotify-module version: latest at 27.01.2022 downloaded from AUR with yay -S polybar-spotify-module

Problem

Ok so the problem looks like this. I start polybar using startup script. Then I run spotify and click play so the polybar module can reload. It works once and then when i switch to a different song it doens't refresh... i tried restarting spotify-listener by systemctl --user restart spotify-listener and it does work.. once ... again :/ so it seems i have to restart spotify-listener in an infinite loop to get it working :/

Vid

Video of problem

Add other metadata tokens for status

In addition to artist and track title, add tokens for other track info such as album name. This may require re-working token format and parsing to avoid adding -length commandline options to each token.

Stopped working on Polybar latest update

I am unable to figure out what's going on, as the daemon is running and spotifyctl is giving the correct output, yet, for some reason, Polybar is showing blank everywhere.

Here's the relevant portion of the Polybar configuration file:

(...)

modules-left = left1 playpause spotify left2

(...)

;; SPOTIFY
[module/playpause]
type = custom/ipc
format-font = 2
format-underline = #1db954
format-background = ${color.shade2}
; Default
hook-0 = echo "  No Song is Playing"
; Playing
hook-1 = echo ""
; Paused
hook-2 = echo ""
click-left = "spotifyctl -q playpause"


[module/spotify]
type = custom/ipc
format-underline = #1db954
format-background = ${color.shade2}
; Default
hook-0 = echo ""
; Playing/paused
hook-1 = spotifyctl -q status

And here's the output when running Polybar on the terminal:

$ polybar
notice: Parsing config file: /home/undercover/.config/polybar/config.ini
notice: Listening for IPC messages (PID: 5499)
warn: The config parameter 'settings.throttle-input-for' is deprecated, it will be removed in the future. Please remove it from your config
warn: The config parameter 'settings.throttle-output' is deprecated, it will be removed in the future. Please remove it from your config
warn: The config parameter 'settings.throttle-output-for' is deprecated, it will be removed in the future. Please remove it from your config
notice: Loading module 'left1' of type 'custom/text'
notice: Loading module 'playpause' of type 'custom/ipc'
notice: Loading module 'spotify' of type 'custom/ipc'
notice: Loading module 'left2' of type 'custom/text'
notice: Loading module 'workspaces' of type 'internal/xworkspaces'
notice: Loading module 'right5' of type 'custom/text'
notice: Loading module 'pulseaudio' of type 'internal/pulseaudio'
notice: pulseaudio: using default sink alsa_output.pci-0000_00_1f.3.analog-stereo
notice: Loading module 'right4' of type 'custom/text'
notice: Loading module 'battery' of type 'internal/battery'
notice: Loading module 'right3' of type 'custom/text'
notice: Loading module 'backlight' of type 'internal/backlight'
notice: Loading module 'right2' of type 'custom/text'
notice: Loading module 'network' of type 'internal/network'
notice: Loading module 'right1' of type 'custom/text'
notice: Loading module 'date' of type 'internal/date'
notice: Loaded 15 modules
notice: Loaded font "Roboto Mono:size=8" (name=Noto Sans, offset=2, file=/usr/share/fonts/noto/NotoSans-Regular.ttf)
notice: Loaded font "Siji:size=12" (name=Siji, offset=2, file=/usr/share/fonts/misc/siji.bdf)
notice: Loaded font "Iosevka Nerd Font:style=Medium:size=16" (name=Iosevka, offset=3, file=/usr/share/fonts/TTF/Iosevka Medium Nerd Font Complete.ttf)
notice: Loaded font "Font Awesome 6 Free:size=14" (name=Font Awesome 6 Free, offset=2, file=/usr/share/fonts/TTF/fa-regular-400.ttf)
error: tray: Failed to put tray above 0x1400001 in the stack (XCB_MATCH (8))

As you can see, everything seems to be alright.

Any tips or ideas on how to proceed the debugging?
Seems to me that I'm missing something quite obvious since it's working on one side and not on the other, yet, I have changed nothing during the update.

Module not loading on startup?

OS : Arch Linux
WM : BSPWM
polybar config :

modules-center = previous spotify next

[module/previous]
type = custom/ipc
format-font = 2
; Default
hook-0 = echo ""
; When spotify active
hook-1 = echo ""
click-left = "spotifyctl -q previous"


[module/next]
type = custom/ipc
format-font = 2
; Default
hook-0 = echo ""
; When spotify active
hook-1 = echo ""
click-left = "spotifyctl -q next"


[module/playpause]
type = custom/ipc
format-font = 2
; Default
hook-0 = echo ""
; Playing
hook-1 = echo ""
; Paused
hook-2 = echo ""
click-left = "spotifyctl -q playpause"


[module/spotify]
type = custom/ipc
; Default
hook-0 = echo ""
; Playing/paused show song name and artist
hook-1 = spotifyctl -q status --format '%artist%: %title%' 

It was working previously and spotifyctl is also working and this is what shows up in polybar log

notice: Parsing config file: /home/greed/.config/polybar/config.ini
notice: Listening for IPC messages (PID: 26465)
notice: Loading module 'xworkspaces' of type 'internal/xworkspaces'
notice: Loading module 'xwindow' of type 'internal/xwindow'
notice: Loading module 'previous' of type 'custom/ipc'
notice: Loading module 'spotify' of type 'custom/ipc'
notice: Loading module 'next' of type 'custom/ipc'
notice: Loading module 'pending' of type 'custom/script'
notice: Loading module 'pulseaudio' of type 'internal/pulseaudio'
notice: pulseaudio: using default sink alsa_output.pci-0000_04_00.6.analog-stereo
notice: Loading module 'memory' of type 'internal/memory'
error: Disabling module "cpu" (reason: Missing section "module/cpu")
notice: Loading module 'wlan' of type 'internal/network'
notice: module/wlan: Discovered wireless interface wlan0
error: Disabling module "eth" (reason: Missing section "module/eth")
notice: Loading module 'date' of type 'internal/date'
notice: Loading module 'battery' of type 'internal/battery'
notice: Loading module 'playpause' of type 'custom/ipc'
notice: Loaded 12 modules
notice: Loaded font "JetBrainsMono Nerd Font Mono:size=12" (name=JetBrainsMono Nerd Font Mono, offset=2, file=/usr/share/fonts/TTF/JetBrains Mono Regular Nerd Font Complete Mono.ttf)
notice: Loaded font "DejaVu Sans Mono wifi ramp" (name=DejaVu Sans Mono wifi ramp, offset=1, file=/usr/share/fonts/TTF/DejaVuSansMono-wifi-ramp.ttf)
notice: Loaded font "JetBrainsMono Nerd Font Mono:size=22" (name=JetBrainsMono Nerd Font Mono, offset=2, file=/usr/share/fonts/TTF/JetBrains Mono Regular Nerd Font Complete Mono.ttf)
notice: Loaded font "JetBrainsMono Nerd Font Mono:size=19" (name=JetBrainsMono Nerd Font Mono, offset=2, file=/usr/share/fonts/TTF/JetBrains Mono Regular Nerd Font Complete Mono.ttf)
notice: Loaded font "Ubuntu Mono Nerd Font:size=13" (name=UbuntuMono Nerd Font, offset=2, file=/usr/share/fonts/TTF/Ubuntu Mono Nerd Font Complete.ttf)
warn: Systray selection already managed (window=0x0a00010)

Is it a dbus issue? or am I doing something wrong?

add support for displaying the time

Hi, I would like if spotifyctl had support for time-seeking, and displaying the current time.

I want this to be able to do something like this
spotifyctl status --format '%title% %time%'
Some title 00:01

Track title update broken ?

It seems the current playing song is not displaying anymore, not sure how I can debug this.

Service is well up and running:

❯ systemctl --user status spotify-listener
● spotify-listener.service - A program that monitors Spotify DBus signals and communicates with polybar over IPC t>
     Loaded: loaded (/usr/lib/systemd/user/spotify-listener.service; enabled; preset: enabled)
     Active: active (running) since Mon 2022-10-24 19:09:43 CEST; 45min ago
   Main PID: 618 (spotify-listene)
      Tasks: 1 (limit: 16593)
     Memory: 412.0K
        CPU: 4ms
     CGroup: /user.slice/user-1000.slice/[email protected]/app.slice/spotify-listener.service
             └─618 /usr/bin/spotify-listener

The command spotifyctl -q status --format '%artist%: %title%' also work as expected. Not sure how I can debug this£

Here's my polybar config FYI

[module/spotify]
type = custom/ipc
hook-0 = echo ""
hook-1 = spotifyctl -q status --format '%artist% - %title%'
initial = 1
format-padding = 1
;format-prefix = 
format-prefix-padding = 1
format-background = ${color.mb}
line-size = 1
; [i3wm only] - Uncomment the below line to focus on Spotify when clicking on the song name (credits to https://github.com/Esya)
click-left = i3-msg '[class="Spotify"] focus'

Not sure how I can properly debug this

Extend player support?

Since all mpris players (are supposed) to follow the same specs, it wouldn't be too difficult to add support for mpris players in general. However, this would require re-branding the entire project.

To add this feature, there would probably need to be an option to exclude players or only include certain players. There would need to be a way to specify this for the listener program and service file (perhaps a config file).

There would also need to be some additional logic to choose a player if there are multiple detected.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.