commit c51a74d5dd21c931553f22627e8f2dcaad8ca0ea Author: mugman Date: Mon Oct 20 10:44:48 2025 -0400 add all the things diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/README.md b/README.md new file mode 100644 index 0000000..d29020b --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# apple music scrobbling for macOS +powered by applescript and python diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f5cff3c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,15 @@ +anyio==4.11.0 +certifi==2025.10.5 +h11==0.16.0 +httpcore==1.0.9 +httpx==0.28.1 +idna==3.11 +py-applescript==1.0.3 +pylast==6.0.0 +pyobjc-core==11.1 +pyobjc-framework-applescriptkit==11.1 +pyobjc-framework-applescriptobjc==11.1 +pyobjc-framework-cocoa==11.1 +python-dotenv==1.1.1 +sniffio==1.3.1 +typing-extensions==4.15.0 diff --git a/scrobbler.py b/scrobbler.py new file mode 100644 index 0000000..db5635a --- /dev/null +++ b/scrobbler.py @@ -0,0 +1,69 @@ +""" +scrobbler +https://gist.github.com/mvrpl/53f1e377315e6db26c47 +""" + +import applescript # py-applescript +import time +import pylast +from dotenv import dotenv_values + +config = dotenv_values(".env") + +lfm = pylast.LastFMNetwork( + api_key=config["LFM_KEY"], + api_secret=config["LFM_SECRET"], + username=config["USERNAME"], + password_hash=pylast.md5(config["PASSWORD"]), +) + +tell_iTunes = applescript.AppleScript(''' +on is_running(appName) + tell application "System Events" to (name of processes) contains appName +end is_running + +on Playing() + set iTunesRunning to is_running("Music") + if iTunesRunning then + tell application "Music" + set songId to the database ID of the current track + set songState to the player state + set songTitle to the name of the current track + set songArtist to the artist of the current track + set songAlbum to the album of the current track + set songAlbumArtist to the album artist of the current track + set songDuration to the duration of the current track + set result to songId & songState & songArtist & songTitle & songAlbum & songDuration & songAlbumArtist + return result + end tell + end if +end Playing +''') +old_id = tracked_id = -1 +runtime = 0 +while True: + time.sleep(1) + try: + out = tell_iTunes.call("Playing") + except Exception as e: + print(e) + continue + id, state, artist, song, album, duration, album_artist = out + print(f"{runtime}/{round(duration)}", end="\r") + if old_id != id: + print("new song", old_id, id, song) + runtime = 0 + old_id = id + if tracked_id == id: + continue + if state.code != b"kPSP": + continue + if duration < 30: + print("not tracking", duration) + old_id = tracked_id = id + continue + runtime += 1 + if (runtime >= duration/2 or runtime > 4*60) and tracked_id != id: + print("scrobbling") + tracked_id = id + lfm.scrobble(artist, song, int(time.time() - runtime), album, album_artist, duration)