Skip to content

Instantly share code, notes, and snippets.

@codiez
Created December 20, 2009 20:14
Show Gist options
  • Save codiez/260617 to your computer and use it in GitHub Desktop.
Save codiez/260617 to your computer and use it in GitHub Desktop.
Listen for distributed notifications from iTunes of the current song
'''
This python script listens for distributed notifications from iTunes of new songs playing, works alot better then constantly polling.
'''
import Foundation
song_details = {}
class GetSongs(object):
def __init__(self):
nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
nc.addObserver_selector_name_object_(self, 'getMySongs:', 'com.apple.iTunes.playerInfo',None)
def getMySongs_(self, song):
ui = song.userInfo()
for x in ui:
song_details[x] = ui.objectForKey_(x)
print song_details
gn = GetSongs()
nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
loop = Foundation.NSRunLoop.currentRunLoop()
loop.run()
@brandondurham
Copy link

While researching methods for logging listens to a database (for creating powerful "Best of the Year" playlists) I found this Gist. Thank you for posting! Could you recommend best methods for logging this information to a DB?

@0a01-wait
Copy link

great info. not familiar with python, im trying to create an applescript observer to watch for distributed notifications from the djay app. do you have an equivalent model of this for applescript? thanks very much

@atchoo78
Copy link

Thanks! I used this as a base script to take it even further and display the current playing track on a dot matrix LED display (via HTTP) connected to my Raspberry PIs GPIO interface.

dotmat

Code (macOS)

import Foundation
from AppKit import *
from PyObjCTools import AppHelper
import requests

LED_URL = "http://raspberrypi.local:8181"

class GetSongs(NSObject):
    def getMySongs_(self, song):
        ui = song.userInfo()
        song_details = dict(zip(ui.keys(), ui.values()))
        nowPlaying = (song_details['Artist'] + " : " + song_details['Name'])
        r = requests.post(url = LED_URL, data = nowPlaying)
        print(nowPlaying)

nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
GetSongs = GetSongs.new()
nc.addObserver_selector_name_object_(GetSongs, 'getMySongs:', 'com.apple.iTunes.playerInfo',None)

NSLog("Listening for new tunes....")
AppHelper.runConsoleEventLoop()

Raspberry PI (Server) code

Luma display library & max7219 display drivers by Richard Hull.

https://github.com/rm-hull/luma.led_matrix

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import re
import argparse
import time
from luma.core.interface.serial import spi, noop
from luma.core.render import canvas
from luma.led_matrix.device import max7219
from luma.core.virtual import viewport
from luma.core.legacy import text, show_message
from luma.core.legacy.font import proportional, CP437_FONT, TINY_FONT, SINCLAIR_FONT, LCD_FONT

serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=3, block_orientation=-90, rotate=2)

class S(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length)
        show_message(device, post_data, fill="white", font=proportional(LCD_FONT))

def run(server_class=HTTPServer, handler_class=S, port=8181):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print 'Starting httpd Server...'
    httpd.serve_forever()

if __name__ == "__main__":
    from sys import argv

    if len(argv) == 2:
        run(port=int(argv[1]))
    else:
        run()

@newPythonUser91
Copy link

Is there a way to return the variable song_details to a python script to be queried later? similar to a basic class in python?

@y4rr
Copy link

y4rr commented Feb 17, 2021

This script works only with system python2. Also, the f*ggot company has renamed iTunes. So here's a couple of needed changes:

#!/usr/bin/python

'''
This python script listens for distributed notifications from iTunes of new songs playing, 
works alot better then constantly polling. 
'''
import Foundation
from AppKit import *
from PyObjCTools import AppHelper

class GetSongs(NSObject):
    def getMySongs_(self, song):
        song_details = {}
        ui = song.userInfo()
        song_details = dict(zip(ui.keys(), ui.values()))
        print song_details

nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
GetSongs = GetSongs.new()
nc.addObserver_selector_name_object_(GetSongs, 'getMySongs:', 'com.apple.Music.playerInfo',None)

NSLog("Listening for new tunes....")
AppHelper.runConsoleEventLoop()

@jim-cooley
Copy link

jim-cooley commented Oct 19, 2021

Runs with Python3, just be sure to install the right PyObjC wrapper, and modify line 1 to point to your python3 installation if its not in the default location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment