-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added menu bar app with basic music player info and controls, Switched to iTunes search API for album art
- Loading branch information
1 parent
b1ea8c2
commit 105de13
Showing
3 changed files
with
185 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from ScriptingBridge import SBObject, SBApplication | ||
import os | ||
import requests | ||
import syslog | ||
|
||
|
||
class Music: | ||
def __init__(self): | ||
self.musicApp = SBApplication.applicationWithBundleIdentifier_("com.apple.Music") | ||
print(self.musicApp.currentTrack().name()) | ||
def getArtURL(self, album, artist): | ||
searchTerm = album.replace(" ", "+") + "+" + artist.split(",")[0].replace(" ", "+") | ||
data = requests.get("https://itunes.apple.com/search?term=" + searchTerm + "&country=us&entity=album&limit=4") | ||
url = "" | ||
|
||
for item in data.json()['results']: | ||
#print(item) | ||
if(item['collectionName'] == album and (item['artistName'] in artist or artist in item['artistName'])): | ||
url = item['artworkUrl100'] | ||
|
||
if url == "": | ||
url = "https://www.iphonefaq.org/files/styles/large/public/apple_music.jpg" | ||
|
||
return url | ||
|
||
def getTrackInfo(self): | ||
# get track info | ||
trackName = str(self.musicApp.currentTrack().name()) | ||
album = str(self.musicApp.currentTrack().album()) | ||
artist = str(self.musicApp.currentTrack().artist()) | ||
year = str(self.musicApp.currentTrack().year()) | ||
|
||
# get image url as well as local copy of image | ||
artURL = self.getArtURL(album, artist) | ||
try: | ||
art = self.musicApp.currentTrack().artworks()[0].rawData().get().data() | ||
if (os.path.exists(os.path.join(os.getenv("HOME"), ".applemusicrp", "albumcover.png")) == False): | ||
os.mkdir(os.path.join(os.getenv("HOME"), ".applemusicrp/")) | ||
art.writeToFile_atomically_(os.path.join(os.getenv("HOME"), ".applemusicrp", "albumcover.png"), False) | ||
|
||
except Exception as e: | ||
print(e) | ||
|
||
return [trackName, album, artist, artURL] | ||
|
||
def getPlayerState(self): | ||
# get player state | ||
playerPosition = self.musicApp.playerPosition() | ||
playing = True if self.musicApp.playerState() == 1800426320 else False | ||
|
||
return [playerPosition, playing] | ||
|
||
def skip(self): | ||
self.musicApp.nextTrack() | ||
|
||
def playPause(self): | ||
self.musicApp.playpause() | ||
|
||
def backtrack(self): | ||
self.musicApp.backTrack() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import rumps | ||
import os | ||
|
||
class StatusBarApp(rumps.App): | ||
def __init__(self, name, icon, music): | ||
super(StatusBarApp, self).__init__(name=name, icon=icon) | ||
self.music = music | ||
self.menu.update([]) | ||
|
||
@rumps.timer(1) | ||
def updateMenu(self,_): | ||
trackInfo = self.music.getTrackInfo() | ||
|
||
self.menu.values()[0].title = trackInfo[0] + " - " + trackInfo[1] | ||
self.menu.values()[0].icon = str(os.path.join(os.getenv("HOME"), ".applemusicrp", "albumcover.png")) | ||
self.menu.values()[0].dimensions=(35,35) | ||
|
||
self.menu.update([]) | ||
|
||
|
||
@rumps.clicked("Play/Pause") | ||
def playPause(self,_): | ||
# playing | ||
playing = self.music.getPlayerState()[1] | ||
if(playing): | ||
self.menu.values()[1].title="Play" | ||
self.updateMenu(_) | ||
|
||
# paused | ||
else: | ||
self.menu.values()[1].title="Pause" | ||
self.updateMenu(_) | ||
|
||
self.music.playPause() | ||
|
||
@rumps.clicked("Skip") | ||
def skip(self, _): | ||
self.music.skip() | ||
self.updateMenu(_) | ||
|
||
@rumps.clicked("Backtrack") | ||
def shuffle(self, _): | ||
self.music.backtrack() | ||
self.updateMenu(_) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,89 @@ | ||
from Foundation import * | ||
from ScriptingBridge import * | ||
import pypresence | ||
#!/usr/bin/env python3.11 | ||
|
||
from ScriptingBridge import SBObject, SBApplication | ||
from pypresence import Presence | ||
import coverpy | ||
from rumps import * | ||
from threading import Thread | ||
|
||
import datetime | ||
import time | ||
import asyncio | ||
import syslog | ||
import requests | ||
|
||
client_id = "PUT-CLIENT-ID-HERE" # find your client ID by creating an application through the discord developer portal | ||
music = SBApplication.applicationWithBundleIdentifier_("com.apple.Music") | ||
import StatusBar | ||
import Music | ||
|
||
|
||
def richPresenceLoop(musicInfo): | ||
# create asynchronous event loop for multithreaded execution | ||
try: | ||
asyncio.get_event_loop() | ||
except: | ||
asyncio.set_event_loop(asyncio.new_event_loop()) | ||
|
||
# application info | ||
client_id = "1084641054055211128" | ||
RPC = Presence(client_id) | ||
|
||
RPC = Presence(client_id) | ||
RPC.connect() | ||
limit = 1 | ||
c = coverpy.CoverPy() | ||
# connect to discord | ||
while True: | ||
try: | ||
RPC.connect() | ||
|
||
except: | ||
time.sleep(2) | ||
|
||
else: | ||
break | ||
|
||
# update rich presence | ||
while True: | ||
try: | ||
trackName, album, artist, artURL = musicInfo.getTrackInfo() | ||
playerPosition = musicInfo.getPlayerState()[0] | ||
RPC.update( | ||
large_image = artURL, | ||
details=trackName | ||
+ " - " | ||
+ album, | ||
state="by " | ||
+ artist | ||
+ " - " | ||
+ str( | ||
datetime.timedelta(minutes=0, seconds=int(playerPosition)) | ||
)[-5:]) | ||
|
||
except: | ||
time.sleep(1) | ||
|
||
else: | ||
time.sleep(1) | ||
|
||
def main(): | ||
|
||
# create music object, get initial info | ||
music = Music.Music() | ||
trackInfo = music.getTrackInfo() | ||
|
||
# start rich presence | ||
richPresence = Thread(target=richPresenceLoop, args=[music]) | ||
richPresence.start() | ||
|
||
# create status bar app | ||
app = StatusBar.StatusBarApp(name="Apple Music Rich Presence", icon="imgs/trayIcon.png", music=music) | ||
|
||
while True: | ||
try: | ||
result = c.get_cover(music.currentTrack().name(), limit) | ||
|
||
except coverpy.exceptions.NoResultsException: | ||
print("Nothing found.") | ||
except requests.exceptions.HTTPError: | ||
print("Could not execute GET request") | ||
|
||
RPC.update( | ||
large_image=result.artwork(100), | ||
details=music.currentTrack().name() + " - " + music.currentTrack().album(), | ||
state=music.currentTrack().artist(), | ||
) | ||
# | ||
# print(music.currentTrack().name() + " - " + music.currentTrack().artist()) | ||
|
||
time.sleep(0.5) | ||
app.menu.add(rumps.MenuItem( | ||
title = trackInfo[0] + " - " + trackInfo[1], | ||
icon='imgs/default_img.png', | ||
dimensions=(35,35))) | ||
app.run() | ||
|
||
except Exception as error: | ||
syslog.syslog(syslog.LOG_ALERT, str(error)) | ||
syslog.syslog(syslog.LOG_ALERT, "except ran") | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |