Add scripts for rofi to play music on spotify
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
configuration {
|
configuration {
|
||||||
modi: "drun,filebrowser,ssh";
|
modes: "drun,filebrowser,ssh";
|
||||||
show-icons: true;
|
show-icons: true;
|
||||||
display-drun: " ";
|
display-drun: " ";
|
||||||
display-run: " ";
|
display-run: " ";
|
||||||
display-ssh: "";
|
display-ssh: "";
|
||||||
display-filebrowser: "";
|
display-filebrowser: " ";
|
||||||
display-window: "";
|
display-window: " ";
|
||||||
|
display-spotify: " ";
|
||||||
drun-display-format: "{name}";
|
drun-display-format: "{name}";
|
||||||
window-format: "{w}{t}";
|
window-format: "{w}{t}";
|
||||||
font: "JetBrainsMono 15";
|
font: "JetBrainsMono 15";
|
||||||
|
|||||||
2
.config/rofi/scripts/requirements.txt
Normal file
2
.config/rofi/scripts/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
joblib==1.5.1
|
||||||
|
spotipy==2.25.1
|
||||||
107
.config/rofi/scripts/spotify.py
Executable file
107
.config/rofi/scripts/spotify.py
Executable file
@@ -0,0 +1,107 @@
|
|||||||
|
#!/home/womax/.config/rofi/scripts/.env/bin/python
|
||||||
|
import joblib
|
||||||
|
from joblib import expires_after
|
||||||
|
import os
|
||||||
|
import os.path as path
|
||||||
|
import shutil
|
||||||
|
import spotipy
|
||||||
|
from spotipy.oauth2 import SpotifyPKCE
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Get client from env variables or default to spotify web player if missing
|
||||||
|
# Using a custom spotify client should be better to avoir rate limiting
|
||||||
|
SPOTIFY_CLIENT_ID = os.getenv(
|
||||||
|
"SPOTIFY_CLIENT_ID",
|
||||||
|
"65b708073fc0480ea92a077233ca87bd")
|
||||||
|
|
||||||
|
cache_dir = path.join(
|
||||||
|
os.getenv("XDG_CACHE_HOME",
|
||||||
|
path.join(os.getenv("HOME"), ".cache")),
|
||||||
|
"rofi-spotify")
|
||||||
|
|
||||||
|
if path.exists(cache_dir) and not path.isdir(cache_dir):
|
||||||
|
shutil.rmtree(cache_dir)
|
||||||
|
|
||||||
|
if not path.exists(cache_dir):
|
||||||
|
os.makedirs(cache_dir, mode=0o755)
|
||||||
|
|
||||||
|
memory = joblib.Memory(cache_dir, verbose=0)
|
||||||
|
|
||||||
|
scopes = ["user-top-read", "user-modify-playback-state"]
|
||||||
|
|
||||||
|
sp = spotipy.Spotify(
|
||||||
|
auth_manager=SpotifyPKCE(
|
||||||
|
client_id=SPOTIFY_CLIENT_ID,
|
||||||
|
redirect_uri="http://127.0.0.1:9090/login",
|
||||||
|
scope=scopes,
|
||||||
|
cache_handler=spotipy.CacheFileHandler(
|
||||||
|
cache_path=path.join(cache_dir, "credentials"))
|
||||||
|
))
|
||||||
|
|
||||||
|
@memory.cache(cache_validation_callback=expires_after(days=30))
|
||||||
|
def get_top_tracks(limit=200):
|
||||||
|
offset = 0
|
||||||
|
tracks = []
|
||||||
|
while offset < limit:
|
||||||
|
reading = min(50, limit-offset)
|
||||||
|
tracks += sp.current_user_top_tracks(
|
||||||
|
limit=reading,
|
||||||
|
offset=offset)["items"]
|
||||||
|
offset += reading
|
||||||
|
return tracks
|
||||||
|
|
||||||
|
def format_track(track):
|
||||||
|
track_format = "{title} - {artist}\0info\x1f{track_id}\n"
|
||||||
|
return track_format.format(
|
||||||
|
title=track["name"],
|
||||||
|
artist=track["artists"][0]["name"],
|
||||||
|
track_id=track["id"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def display_default():
|
||||||
|
liked_tracks = get_top_tracks()
|
||||||
|
for item in liked_tracks:
|
||||||
|
print(format_track(item), end="")
|
||||||
|
|
||||||
|
def play_track(track_id: str):
|
||||||
|
try:
|
||||||
|
sp.add_to_queue(f"spotify:track:{track_id}")
|
||||||
|
except spotipy.SpotifyException as err:
|
||||||
|
print(f"\0message\x1f{err.msg}")
|
||||||
|
return
|
||||||
|
time.sleep(0.1)
|
||||||
|
sp.next_track()
|
||||||
|
|
||||||
|
@memory.cache(cache_validation_callback=expires_after(seconds=180))
|
||||||
|
def search_track(query: str):
|
||||||
|
try:
|
||||||
|
query_res = sp.search(query, limit=30, type='track')["tracks"]["items"]
|
||||||
|
if len(query_res) == 0:
|
||||||
|
print("\0message\x1fNo result in search")
|
||||||
|
return
|
||||||
|
for result in query_res:
|
||||||
|
print(format_track(result), end="")
|
||||||
|
except spotipy.SpotifyException as err:
|
||||||
|
print(f"\0message\x1f{err.msg}")
|
||||||
|
return
|
||||||
|
|
||||||
|
def main():
|
||||||
|
match int(os.getenv("ROFI_RETV", default=-1)):
|
||||||
|
case 0:
|
||||||
|
# Initial call
|
||||||
|
display_default()
|
||||||
|
case 1:
|
||||||
|
# Selected entry
|
||||||
|
play_track(os.getenv("ROFI_INFO", ""))
|
||||||
|
exit(0)
|
||||||
|
case 2:
|
||||||
|
# Custom entry
|
||||||
|
track = sys.argv[1]
|
||||||
|
search_track(track)
|
||||||
|
memory.reduce_size(bytes_limit="10M")
|
||||||
|
case _:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if __name__=="__main__":
|
||||||
|
main()
|
||||||
3
.zshrc
3
.zshrc
@@ -58,3 +58,6 @@ eval "$(zoxide init --cmd cd zsh)"
|
|||||||
eval "$(fzf --zsh)"
|
eval "$(fzf --zsh)"
|
||||||
eval "$(oh-my-posh init zsh --config '~/.p10k.omp.yml')"
|
eval "$(oh-my-posh init zsh --config '~/.p10k.omp.yml')"
|
||||||
#eval "$(~/Dev/oh-my-posh/src/omp init zsh --config '~/.p10k.omp.yml')"
|
#eval "$(~/Dev/oh-my-posh/src/omp init zsh --config '~/.p10k.omp.yml')"
|
||||||
|
|
||||||
|
# Created by `pipx` on 2025-08-18 19:52:55
|
||||||
|
export PATH="$PATH:/home/womax/.local/bin"
|
||||||
|
|||||||
Reference in New Issue
Block a user