From c8022bdef4276d493d096ecde9458638d89307de Mon Sep 17 00:00:00 2001 From: Remi Akirazar Date: Thu, 13 Nov 2025 16:39:46 -0500 Subject: [PATCH] remove emacs *~ files --- .gitignore | 3 +- __pycache__/config.cpython-313.pyc | Bin 17585 -> 0 bytes __pycache__/spotify.cpython-313.pyc | Bin 7906 -> 0 bytes spotify.py~ | 204 ---------------------------- 4 files changed, 2 insertions(+), 205 deletions(-) delete mode 100644 __pycache__/config.cpython-313.pyc delete mode 100644 __pycache__/spotify.cpython-313.pyc delete mode 100644 spotify.py~ diff --git a/.gitignore b/.gitignore index ed8ebf5..5979577 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -__pycache__ \ No newline at end of file +__pycache__ +*~ \ No newline at end of file diff --git a/__pycache__/config.cpython-313.pyc b/__pycache__/config.cpython-313.pyc deleted file mode 100644 index b78504696975051d805c4e0f607332f962792dc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17585 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�+r%ezRx`M*u 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 diff --git a/__pycache__/spotify.cpython-313.pyc b/__pycache__/spotify.cpython-313.pyc deleted file mode 100644 index 4e1c71d5dce38ab0e2167ebada33c7f4550f8f22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7906 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 diff --git a/spotify.py~ b/spotify.py~ deleted file mode 100644 index c5de735..0000000 --- a/spotify.py~ +++ /dev/null @@ -1,204 +0,0 @@ -# The MIT License (MIT) - -# Copyright(c) 2022 Ben Hunt - -# 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. - -from subprocess import CompletedProcess, run -from typing import List - -from libqtile.group import _Group -from libqtile.config import Screen - -from libqtile.widget import base -from libqtile.log_utils import logger - -SPOTIFY = "Spotify" - - -class Spotify(base.ThreadPoolText): - """ - A widget to interact with spotify via dbus. - """ - - defaults = [ - ("play_icon", "", "icon to display when playing music"), - ("pause_icon", "", "icon to display when music paused"), - ("update_interval", 0.5, "polling rate in seconds"), - ("format", "{icon} {artist}:{album} - {track}", "Spotify display format"), - ] - - def __init__(self, **config) -> None: - # init base class - super().__init__(text="", **config) - self.add_defaults(Spotify.defaults) - self.add_callbacks( - { - "Button1": self.toggle_music, - } - ) - - def _is_proc_running(self, proc_name: str) -> bool: - # create regex pattern to search for to avoid similar named processes - pattern = f"{proc_name}$" - # pgrep will return a string of pids for matching processes - cmd = ["pgrep", "-fli", pattern] - proc_out = run(cmd, capture_output=True).stdout.decode( - "utf-8" - ) - - return proc_out != "" - - def toggle_between_groups(self) -> None: - """ - remember which group you were on before you switched to spotify - so you can toggle between the 2 groups - """ - current_screen: Screen = self.qtile.current_screen - current_group_info = self.qtile.current_group.info() - logger.warning(f"current group info: {current_group_info}") - windows = current_group_info["windows"] - if SPOTIFY in windows: - # go to previous group - logger.warning("going to previous group") - current_screen.group.get_previous_group().toscreen() - logger.warning("went to previous group") - else: - self.go_to_spotify() - - def go_to_spotify(self) -> None: - """ - Switch to whichever group has the current spotify instance - if none exists then we will spawn an instance on the current group - """ - # spawn spotify if not already running - if not self._is_proc_running("spotify"): - self.qtile.spawn("spotify", shell=True) - return - - all_groups: List[_Group] = self.qtile.groups - # we need to find the group that has spotify in it - for group in all_groups: - info = group.info() - # get a list of windows for the group. We look for 'Spotify here' - windows = info["windows"] - if SPOTIFY in windows: - name = group.name - # switch to 'name' group - spotify_group = self.qtile.groups_map[name] - spotify_group.toscreen() - break - - def poll(self) -> str: # type: ignore - """Poll content for the text box""" - vars = { - "icon": self.pause_icon if self.playing else self.play_icon, - "artist": self.artist, - "track": self.song_title, - "album": self.album, - } - - return self.format.format(**vars) # type: ignore - - def toggle_music(self) -> None: - cmd = """ - dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify \ - /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause - """ - run(cmd, shell=True) - - - def get_proc_output(self, proc: CompletedProcess) -> str: - stdout = proc.stdout.decode("utf-8") - no_spotify = "Error" in stdout - return ( - "" - if no_spotify - else stdout.rstrip() - ) - - - @property - def _meta(self) -> str: - cmd = """dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify \ - /org/mpris/MediaPlayer2 \ - org.freedesktop.DBus.Properties.Get \ - string:'org.mpris.MediaPlayer2.Player' \ - string:'Metadata' - """ - proc = run( cmd, shell=True, capture_output=True) - - output: str = proc.stdout.decode("utf-8").replace("'", "ʼ").rstrip() - return "" if ("org.mpris.MediaPlayer2.spotify" in output) else output - - @property - def artist(self) -> str: - cmd =""" - dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify \ - /org/mpris/MediaPlayer2 \ - org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' \ - string:'Metadata' | grep -m1 'xesam:artist' -b2 | tail -n 1 | grep -o '\".*\"' | \ - sed 's/\"//g' | sed -e 's/&/and/g' - """ - proc: CompletedProcess = run(cmd, - shell=True, - capture_output=True, - ) - - return self.get_proc_output(proc) - - @property - def song_title(self) -> str: - cmd = f""" - echo '{self._meta}' | grep -m1 'xesam:title' -b1 | tail -n1 | grep -o '\".*\"' | \ - sed 's/\"//g' | sed -e 's/&/and/g' - """ - proc: CompletedProcess = run(cmd, - shell=True, - capture_output=True - ) - - return self.get_proc_output(proc) - - @property - def album(self) -> str: - cmd = f""" - echo '{self._meta}' | grep -m1 'xesam:album' -b1 | tail -n1 | grep -o '\".*\"' | \ - sed 's/\"//g' | sed -e 's/&/and/g' - """ - proc = run(cmd, - shell=True, - capture_output=True, - ) - - return self.get_proc_output(proc) - - @property - def playing(self) -> bool: - cmd = """ - dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify \ - /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get \ - string:'org.mpris.MediaPlayer2.Player' string:'PlaybackStatus' | grep -o Playing - """ - play = run(cmd, - shell=True, - capture_output=True, - ).stdout.decode("utf-8") - - return play != ""