Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
[#]*[#]
.\#*
.swp
vendor/bundle/
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ Show battery status.

#### Bspwm (Experimental)

**Requires Bspwm**. Shows desktops for selected monitor. and highlights focused one. Unfocused desktops are clickable. Could do with some optimization work and feedback from people that use BSP frequently, especially with multiple monitors.
**Requires Bspwm**. Shows desktops for selected monitor. and highlights focused one. Unfocused desktops are clickable. Could do with some optimization work and feedback from people that use BSP frequently, especially with multiple monitors.

`bsp = Barr::Blocks::Bspwm.new monitor: "DP-4", invert_focus_colors: true`
`bsp = Barr::Blocks::Bspwm.new monitor: "DP-4", invert_focus_colors: true`

| Option | Value | Description | Default |
| --- | --- | --- | --- |
Expand All @@ -190,8 +190,8 @@ Shows the current date and/or time.
`conky = Barr::Blocks::Conky.new string: "${cpu}"`

| Option | Value | Description | Default |
| --- | --- | --- | --- |
| `text` | Conky 'TEXT' string | String made up of [one or more conky variables](http://conky.sourceforge.net/variables.html), as you might find in the `TEXT` section of a conkyrc | **REQUIRED** |
| --- | --- | --- | --- |
| `text` | Conky 'TEXT' string | String made up of [one or more conky variables](http://conky.sourceforge.net/variables.html), as you might find in the `TEXT` section of a conkyrc | **REQUIRED** |

#### CPU

Expand Down Expand Up @@ -261,7 +261,6 @@ There are no `Processes` block specific configurable options.
| `buttons` | bool | As above, but for the player control buttons | `true` |
| `title` | bool | As above, but for the track title | `true` |


#### Separator

This block is a simple string to be used as a separator between other blocks.
Expand All @@ -270,6 +269,17 @@ This block is a simple string to be used as a separator between other blocks.
| --- | --- | --- | --- |
| `symbol` | any string | The string to use as a separator | `|`

#### Spotify

**Requires Spotify**. Shows currently playing artist and/or track, as well as control buttons. Control buttons use FontAwesome.

`rb = Barr::Blocks::Spotify.new buttons: false`

| Option | Value | Description | Default |
| --- | --- | --- | --- |
| `artist` | bool | Set to `true` or `false` to set whether or not the currently playing artist should be shown. | `true` |
| `buttons` | bool | As above, but for the player control buttons | `true` |
| `title` | bool | As above, but for the track title | `true` |

#### Temperature

Expand Down
2 changes: 2 additions & 0 deletions barr.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ Gem::Specification.new do |spec|

spec.add_runtime_dependency "i3ipc", "0.2.0"
spec.add_runtime_dependency "weather-api", "1.2.0"
spec.add_runtime_dependency "ruby-dbus", "~> 0.11.0"

spec.requirements << "Lemonbar with XFT support (https://github.com/krypt-n/bar)"
spec.requirements << "(Optional) I3 for Workspace support"
spec.requirements << "(Optional) RhythmBox & rhythmbox-client"
spec.requirements << "(Optional) Spotify"
spec.requirements << "(Optional) FontAwesome font"
end
1 change: 1 addition & 0 deletions lib/barr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require 'barr/blocks/mem'
require 'barr/blocks/processes'
require 'barr/blocks/rhythmbox'
require 'barr/blocks/spotify'
require 'barr/blocks/temperature'
require 'barr/blocks/whoami'
require 'barr/blocks/separator'
Expand Down
89 changes: 89 additions & 0 deletions lib/barr/blocks/spotify.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# coding: utf-8
require 'barr/block'
require 'dbus'

module Barr
module Blocks
class Spotify < Block
DBUS_PLAY = 'dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause'.freeze
DBUS_NEXT = 'dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Next'.freeze
DBUS_PREV = 'dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Previous'.freeze

attr_reader :view_opts, :spotify_iface

def initialize(opts = {})
super

@view_opts = {
artist: opts[:artist].nil? || opts[:artist],
buttons: opts[:buttons].nil? || opts[:buttons],
title: opts[:title].nil? || opts[:title]
}
@spotify_iface = dbus_connection
end

def update!
op = []

if @view_opts[:artist] || @view_opts[:title]
if(running?)
info = sys_cmd[:foo]

if @view_opts[:artist] && @view_opts[:title]
op << "#{info[:artist]} - #{info[:title]}"
elsif @view_opts[:artist]
op << info[:artist]
elsif @view_opts[:title]
op << info[:title]
end
else
op << 'None'
end
end

op << buttons if @view_opts[:buttons]

@output = op.join(' ')

end

def running?
`pgrep spotify`.chomp.length != 0
end

def buttons
[
"%{A:#{DBUS_PREV}:}\uf048%{A}",
"%{A:#{DBUS_PLAY}:}\uf04b%{A}",
"%{A:#{DBUS_NEXT}:}\uf051%{A}"
].join(' ').freeze
end

def dbus_connection
begin
spotify_service = DBus.session_bus['org.mpris.MediaPlayer2.spotify']
spotify_player = spotify_service.object '/org/mpris/MediaPlayer2'
spotify_player.introspect
rescue DBus::Error
# This should only happen when testing and Spotify is not running,
# because DBus cannot find a service file that provides
# org.mpris.MediaPlayer2.spotify. This will not be an issue with
# typical usage as long as #running? is checked before using this
# method or #sys_cmd.
return nil
else
return spotify_player['org.mpris.MediaPlayer2.Player']
end
end

private

def sys_cmd
dbus_meta = @spotify_iface['Metadata']
Hash.new title: dbus_meta['xesam:title'],
artist: dbus_meta['xesam:artist'].join(', '),
album: dbus_meta['xesam:album']
end
end
end
end
84 changes: 84 additions & 0 deletions spec/blocks/spotify_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# coding: utf-8
require 'barr/blocks/spotify'
require './spec/mocks/spotify'

RSpec.describe Barr::Blocks::Spotify do
let(:sys_cmd) { Hash.new(title: 'Tear In My Heart',
artist: ['Twenty One Pilots'].join(', '),
album: 'Blurryface') }
let(:dbus_play) { 'dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause' }
let(:dbus_next) { 'dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Next' }
let(:dbus_prev) { 'dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Previous' }

before do
allow(subject).to receive(:running?).and_return(true)
allow(subject).to receive(:sys_cmd).and_return(sys_cmd)
allow(subject).to receive(:spotify_iface).and_return(SpotifyDbusMock.new)
end

describe '#initialize' do
it 'sets the default options' do
expect(subject.view_opts[:artist]).to eq true
expect(subject.view_opts[:buttons]).to eq true
expect(subject.view_opts[:title]).to eq true
end

it 'sets a DBus connection' do
subject { described_class.new }
expect(subject.spotify_iface).to be_a(SpotifyDbusMock)
end
end

describe '#update' do
context 'with everything enabled' do
before { subject.update! }

it 'sets the output correctly' do
expect(subject.output).to eq("Twenty One Pilots - Tear In My Heart %{A:#{dbus_prev}:}%{A} %{A:#{dbus_play}:}%{A} %{A:#{dbus_next}:}%{A}")
end
end

context 'with only artist enabled' do
subject { described_class.new title: false, buttons: false }

before { subject.update! }

it 'sets the output correctly' do
expect(subject.output).to eq('Twenty One Pilots')
end
end

context 'with only title enabled' do
subject { described_class.new artist: false, buttons: false }

before { subject.update! }

it 'sets the output correctly' do
expect(subject.output).to eq('Tear In My Heart')
end
end

context 'with only buttons enabled' do
subject { described_class.new title: false, artist: false }

before { subject.update! }

it 'sets the output correctly' do
expect(subject.output).to eq("%{A:#{dbus_prev}:}%{A} %{A:#{dbus_play}:}%{A} %{A:#{dbus_next}:}%{A}")
end
end

context 'when nothing is playing' do
subject { described_class.new buttons: false }

before do
allow(subject).to receive(:running?).and_return(false)
subject.update!
end

it 'sets the output correctly' do
expect(subject.output).to eq('None')
end
end
end
end
19 changes: 19 additions & 0 deletions spec/mocks/spotify.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class SpotifyDbusMock
def [](_key)
MetadataMock.new
end
end

class MetadataMock
def [](key)
if key == 'xesam:title'
return 'Tear In My Heart'
elsif key == 'xesam:artist'
return ['Twenty One Pilots']
elsif key == 'xesam:album'
return 'Blurryface'
else
raise "I don't know what to do with that key"
end
end
end