aboutsummaryrefslogtreecommitdiffstats
path: root/polybar/.local/bin
diff options
context:
space:
mode:
authorPeter Son Struschka <me@peter-struschka.com>2021-02-28 17:58:30 +0800
committerPeter Son Struschka <me@peter-struschka.com>2021-02-28 17:58:30 +0800
commit83d7b9c7ce20f16681afacf99ed3ab47427f1ded (patch)
tree5f607e348dadf13e5d6061217b7a317a48527d83 /polybar/.local/bin
parente5209aad576fe44d3965fcb94d6709348b0a93bf (diff)
downloaddotfiles-83d7b9c7ce20f16681afacf99ed3ab47427f1ded.tar.gz
dotfiles-83d7b9c7ce20f16681afacf99ed3ab47427f1ded.tar.bz2
dotfiles-83d7b9c7ce20f16681afacf99ed3ab47427f1ded.tar.lz
dotfiles-83d7b9c7ce20f16681afacf99ed3ab47427f1ded.tar.xz
dotfiles-83d7b9c7ce20f16681afacf99ed3ab47427f1ded.tar.zst
dotfiles-83d7b9c7ce20f16681afacf99ed3ab47427f1ded.zip
all: fixes and new modules
Diffstat (limited to 'polybar/.local/bin')
-rwxr-xr-xpolybar/.local/bin/playercl246
-rwxr-xr-xpolybar/.local/bin/spotifycl74
2 files changed, 296 insertions, 24 deletions
diff --git a/polybar/.local/bin/playercl b/polybar/.local/bin/playercl
new file mode 100755
index 0000000..83f4a40
--- /dev/null
+++ b/polybar/.local/bin/playercl
@@ -0,0 +1,246 @@
+#!/usr/bin/env python
+
+# MIT License
+#
+# Copyright (c) 2018 Andreas Backx
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""Spotify DBus listener"""
+
+
+import os
+import socket
+import logging
+from concurrent.futures import ThreadPoolExecutor
+
+import click
+import dbus # type: ignore
+import dbus.mainloop.glib # type: ignore
+from dbus.mainloop.glib import DBusGMainLoop
+from gi.repository import GLib # type: ignore
+#from spotipy import SpotifyException
+#from spotipy.oauth2 import SpotifyClientCredentials
+
+INACTIVE_COLOR = '%{F#6E6E6E}'
+ACTIVE_COLOR = '%{F#CECECE}'
+DEFAULT_COLOR = '%{F-}'
+
+SERVER_ADDRESS = '/tmp/playercl-socket'
+LOG_FILE = '/tmp/playercl.log'
+
+
+
+class Playercl:
+ """MediaPlayer DBus Listener"""
+
+ # pylint: disable=too-many-instance-attributes
+
+ MEDIA_PLAYER_PREFIX = 'org.mpris.MediaPlayer2'
+
+ SPOTIFY_BUS = 'org.mpris.MediaPlayer2.spotify'
+ SPOTIFYD_BUS = 'org.mpris.MediaPlayer2.spotifyd'
+ MPRIS_OBJECT_PATH = '/org/mpris/MediaPlayer2'
+
+ PLAYER_INTERFACE = 'org.mpris.MediaPlayer2.Player'
+ PROPERTIES_INTERFACE = 'org.freedesktop.DBus.Properties'
+
+ SAVE_REMOVE = b'save'
+
+ logging.basicConfig(filename=LOG_FILE, filemode='w', level=logging.DEBUG)
+ logger = logging.getLogger("playercl")
+
+ def __init__(self):
+ DBusGMainLoop(set_as_default=True)
+ self.session_bus = dbus.SessionBus()
+ self.last_output = ''
+
+ self.player_objects = dict()
+ self.current_player = None
+
+ # Last shown metadata
+ self.last_title = None
+ # Whether the current song is added to the library
+ self.saved_track = False
+ # Whether to ignore the update
+ self.ignore = False
+ # DBus session object
+ self.freedesktop = None
+
+ def monitor(self):
+ """ Monitor """
+ self.logger.info("monitor")
+ self.locate_player_services()
+ self.freedesktop = self.session_bus.get_object(
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus"
+ )
+ self.freedesktop.connect_to_signal(
+ "NameOwnerChanged",
+ self.on_name_owner_changed
+ )
+
+ executor = ThreadPoolExecutor(max_workers=2)
+ executor.submit(self._start_glib_loop)
+ executor.submit(self._start_server)
+
+ @staticmethod
+ def _start_glib_loop():
+ """ Start Glib loop """
+ loop = GLib.MainLoop()
+ loop.run()
+
+ @staticmethod
+ def _start_server():
+ try:
+ os.unlink(SERVER_ADDRESS)
+ except OSError:
+ if os.path.exists(SERVER_ADDRESS):
+ raise
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.bind(SERVER_ADDRESS)
+ sock.listen(5)
+
+ @property
+ def empty_output(self):
+ """ is output empty"""
+ return not self.last_output
+
+ @property
+ def metadata_status(self):
+ """ Get song status """
+ properties = self.get_current_player_properties()
+ metadata = properties.Get(
+ Playercl.PLAYER_INTERFACE,
+ 'Metadata'
+ )
+ playback_status = properties.Get(
+ Playercl.PLAYER_INTERFACE,
+ 'PlaybackStatus'
+ )
+ return metadata, playback_status
+
+ def output(self, line):
+ """ Output for polybar """
+ if line != self.last_output:
+ print(line, flush=True)
+ self.last_output = line
+
+ def locate_player_services(self):
+ """ Get all players """
+ self.logger.info("Find services")
+ for service in self.session_bus.list_names():
+ if service.startswith(self.MEDIA_PLAYER_PREFIX):
+ self.logger.info("service: %s", service)
+ self.add_player_service(service)
+
+ def output_playback_status(self, data, retry=False):
+ """ output current song """
+ if self.ignore:
+ return
+
+ if 'Metadata' not in data or 'xesam:artist' not in data:
+ self.output('')
+
+ metadata = data['Metadata']
+ artists = metadata['xesam:artist']
+ artist = artists[0] if artists else None
+ artist_string = f'{artist} -' if artist else ''
+
+ title = metadata['xesam:title']
+ playback_status = data['PlaybackStatus']
+ same_song = title == self.last_title
+
+ color = ACTIVE_COLOR if playback_status == 'Playing' else INACTIVE_COLOR
+ # divider = '+' if same_song and self.saved_track else '-'
+ self.output(f'{color}{artist_string}{title}{DEFAULT_COLOR}')
+
+ if not same_song:
+ self.last_title = title
+
+ def on_properties_changed(self, interface, data, *args, **kwargs):
+ """On name properties changed event"""
+ self.logger.info("properties_changed: %s, %s, %s, %s", interface, data, args, kwargs)
+ self.output_playback_status(data)
+
+ def set_current_player(self, name):
+ """ set the current player by getting what's currently playing"""
+ self.current_player = name
+
+ def get_current_player_properties(self):
+ """ return the player intefrace for the current player """
+ property_interface = dbus.Interface(
+ self.player_objects[self.current_player],
+ dbus_interface=self.PROPERTIES_INTERFACE)
+ return property_interface
+
+ def add_player_service(self, service, path=None):
+ """ Add a service to our known list of players """
+ self.logger.info("add player service: %s", service)
+ if not path:
+ path = self.MPRIS_OBJECT_PATH
+ try:
+ player = self.session_bus.get_object(service, path)
+ self.player_objects[service] = player
+ player.connect_to_signal(
+ "PropertiesChanged",
+ self.on_properties_changed,
+ sender_keyword='sender',
+ path_keyword='path')
+ self.set_current_player(service)
+ if self.empty_output:
+ metadata, playback_status = self.metadata_status
+ self.output_playback_status(
+ data={
+ 'Metadata': metadata,
+ 'PlaybackStatus': playback_status,
+ }
+ )
+ except dbus.DBusException as error:
+ self.logger.warning("Exception: %s", error)
+
+ def on_name_owner_changed(self, name, old_owner, new_owner):
+ """On name owner changed event"""
+ if name.startswith(self.MEDIA_PLAYER_PREFIX):
+ self.logger.info("name owner changed: name: %s old: %s new: %s", name, old_owner, new_owner or "Removed")
+ if not old_owner: # new object
+ self.add_player_service(name)
+ elif not new_owner:
+ del self.player_objects[name]
+
+ # if old_owner is None then new object
+ # if new_owner is None then deleted
+ # check name for MPRIS prefix then add to self.player_objects if
+ # not in list
+
+
+@click.group()
+def cli():
+ """Script for listening to Spotify over dbus and adding tracks to your library."""
+
+
+@cli.command()
+def status():
+ """Follow the status of the currently playing song on Spotify."""
+ player = Playercl()
+ player.monitor()
+
+
+if __name__ == '__main__':
+ cli()
diff --git a/polybar/.local/bin/spotifycl b/polybar/.local/bin/spotifycl
index ffee9f0..f7ced52 100755
--- a/polybar/.local/bin/spotifycl
+++ b/polybar/.local/bin/spotifycl
@@ -22,32 +22,34 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+"""Spotify DBus listener"""
+
import os
import socket
-import sys
-import time
-import traceback
+import logging
from concurrent.futures import ThreadPoolExecutor
import click
-import dbus
-import dbus.mainloop.glib
-import spotipy
-import spotipy.util as util
+import dbus # type: ignore
+import dbus.mainloop.glib # type: ignore
from dbus.mainloop.glib import DBusGMainLoop
-from gi.repository import GLib
-from spotipy import SpotifyException
-from spotipy.oauth2 import SpotifyClientCredentials
+from gi.repository import GLib # type: ignore
+#from spotipy import SpotifyException
+#from spotipy.oauth2 import SpotifyClientCredentials
+
+INACTIVE_COLOR = '%{F#6E6E6E}'
+ACTIVE_COLOR = '%{F#CECECE}'
+DEFAULT_COLOR = '%{F-}'
-inactive_color = '%{F#6E6E6E}'
-active_color = '%{F#CECECE}'
-default_color = '%{F-}'
+SERVER_ADDRESS = '/tmp/spotifycl-socket'
-server_address = '/tmp/spotifycl-socket'
class Spotify:
+ """Spotify DBus Listener"""
+
+ # pylint: disable=too-many-instance-attributes
SPOTIFY_BUS = 'org.mpris.MediaPlayer2.spotify'
SPOTIFYD_BUS = 'org.mpris.MediaPlayer2.spotifyd'
@@ -58,6 +60,9 @@ class Spotify:
SAVE_REMOVE = b'save'
+ logging.basicConfig(filename="/tmp/spotifycl.log", level=logging.DEBUG)
+ logger = logging.getLogger("spotifycl")
+
def __init__(self):
DBusGMainLoop(set_as_default=True)
self.session_bus = dbus.SessionBus()
@@ -70,8 +75,13 @@ class Spotify:
self.saved_track = False
# Whether to ignore the update
self.ignore = False
+ # DBus session object
+ self.freedesktop = None
+ self.spotify = None
def monitor(self):
+ """ Monitor """
+ self.logger.info("monitor")
self.setup_properties_changed()
self.freedesktop = self.session_bus.get_object(
"org.freedesktop.DBus",
@@ -87,22 +97,26 @@ class Spotify:
executor.submit(self._start_glib_loop)
executor.submit(self._start_server)
- def _start_glib_loop(self):
+ @staticmethod
+ def _start_glib_loop():
+ """ Start Glib loop """
loop = GLib.MainLoop()
loop.run()
- def _start_server(self):
+ @staticmethod
+ def _start_server():
try:
- os.unlink(server_address)
+ os.unlink(SERVER_ADDRESS)
except OSError:
- if os.path.exists(server_address):
+ if os.path.exists(SERVER_ADDRESS):
raise
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- sock.bind(server_address)
+ sock.bind(SERVER_ADDRESS)
sock.listen(5)
@property
def metadata_status(self):
+ """ Get song status """
spotify_properties = dbus.Interface(
self.spotify,
dbus_interface=Spotify.PROPERTIES_INTERFACE
@@ -118,6 +132,7 @@ class Spotify:
return metadata, playback_status
def output(self, line):
+ """ Output for polybar """
if not line:
self.empty_output = True
if line != self.last_output:
@@ -125,15 +140,21 @@ class Spotify:
self.last_output = line
def setup_spotify(self):
+ """ Setup spotify DBus session object """
+ self.logger.info("setup spotify")
try:
self.spotify = self.session_bus.get_object(
Spotify.SPOTIFY_BUS,
Spotify.SPOTIFY_OBJECT_PATH
)
- except dbus.DBusException:
- self.spotify = self.session_bus.get_object(Spotify.SPOTIFYD_BUS, Spotify.SPOTIFY_OBJECT_PATH)
+ except dbus.DBusException as error:
+ self.logger.warning("DbusException: %s", error)
+ self.spotify = self.session_bus.get_object(
+ Spotify.SPOTIFYD_BUS,
+ Spotify.SPOTIFY_OBJECT_PATH)
def setup_properties_changed(self):
+ """ Setup propertise changed """
try:
self.setup_spotify()
self.spotify.connect_to_signal(
@@ -151,9 +172,11 @@ class Spotify:
)
except dbus.DBusException:
+ self.logger.warning("Exception")
self.output('')
def output_playback_status(self, data, retry=False):
+ """ output current song """
if self.ignore:
return
@@ -169,17 +192,21 @@ class Spotify:
playback_status = data['PlaybackStatus']
same_song = title == self.last_title
- color = active_color if playback_status == 'Playing' else inactive_color
+ color = ACTIVE_COLOR if playback_status == 'Playing' else INACTIVE_COLOR
# divider = '+' if same_song and self.saved_track else '-'
- self.output(f'{color}{artist} - {title}{default_color}')
+ self.output(f'{color}{artist} - {title}{DEFAULT_COLOR}')
if not same_song:
self.last_title = title
def on_properties_changed(self, interface, data, *args, **kwargs):
+ """On name properties changed event"""
+ del interface, args, kwargs
self.output_playback_status(data)
def on_name_owner_changed(self, name, old_owner, new_owner):
+ """On name owner changed event"""
+ del old_owner
if name == self.SPOTIFY_BUS:
if new_owner:
# Spotify was opened.
@@ -193,7 +220,6 @@ class Spotify:
@click.group()
def cli():
"""Script for listening to Spotify over dbus and adding tracks to your library."""
- pass
@cli.command()