Python Script to tweet last.fm scrobbles

A silly conceit, but fun. The script is pretty simple (read: I’m an unsophisticated programmer), but it works. Because it hooks into last.fm, anything you scrobble (Roon, Spotify, iTunes, your player of choice) shows up.

I run it manually right now, but it could be cron’d.

#!/usr/bin/env /Library/Frameworks/Python.framework/Versions/3.7/bin/python3

# Installed Python 3.7 for Mac from python.org

import os
import json
import sys
import twitter # Installed python-twitter (https://python-twitter.readthedocs.io/en/latest/installation.html)
import requests

# Twitter API Setup -- the twitter API information has to come from your Twitter account

consumer_key = '[Twitter Consumer Key]'
consumer_secret = '[Twitter Consumer Secret]'
access_key = '[Twitter Access Key]'
access_secret = '[Twitter Access Secret]'
api = twitter.Api(consumer_key=consumer_key, consumer_secret=consumer_secret,
                      access_token_key=access_key, access_token_secret=access_secret)
                      
# Files we use -- this is where my files live, but you will need to use your own filepath

scrobbleDir =  os.path.join('/', 'Users', 'onlylooksharmless', 'Documents','Scripts', 'Scrobble to Twitter')
lastScrobbleFileLoc = os.path.join(scrobbleDir, 'lastscrobble.txt')
tweetErrFileLoc = os.path.join(scrobbleDir, 'tweeterr.txt')

# Get last date from stored file, increment by one, reset to string
# Consider using shelve module (https://automatetheboringstuff.com/chapter8/) in next version
# The very first time you run it, I'd recommend using a browser to pull the last NN scrobbles, and you can pick out a UTS to put in the file

lastScrobbleFile = open(lastScrobbleFileLoc)
startTime = lastScrobbleFile.read()
lastScrobbleFile.close
startTime = str(int(startTime) + 1)

# Get Scrobbles and set up iteration
# Block Comment is what I used to test against a downloaded JSON file

'''samplePath = os.path.join('/', 'Users', 'onlylooksharmless', 'Documents', 'Scripts', 'Scrobble to Twitter', 'Dev Process', 'Sample Scrobble.json')
sampleFile = open(samplePath)
scrobbleList=sampleFile.read()
scrobbleListAsPython = json.loads(scrobbleList)'''

# last.fm API call using startTime
# It works to increment last dateStamp by 1, append &from=[incremented] at end
# You have to get your own last.fm user name and api key 

scrobbleURL ='http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&&user=[USERNAME]&api_key=[APIKEY]&format=json&from=%s' % (startTime)
try:
	scrobbleList = requests.get(scrobbleURL)
except:
	tweetErrFile = open(tweetErrFileLoc, 'a')
	tweetErrFile.write('last.fm unavailable')
	tweetErrFile.close()
	sys.exit(2)
scrobbleList.raise_for_status()
scrobbleListAsPython = json.loads(scrobbleList.text) # I used JSON for no better reason that it's what "Automate the Boring Stuff worked with."
trackList = scrobbleListAsPython['recenttracks']['track']
trackListLen = len(trackList)

# Check to make sure Twitter is up; bail if not

try:
	twitterTest = requests.get('http://twitter.com')
except:
	tweetErrFile = open(tweetErrFileLoc, 'a')
	tweetErrFile.write('twitter unavailable')
	tweetErrFile.close()
	sys.exit(2)


# Create the blank tweet list
# Goal of creating uniques is to reduce Twitter duplicate tweet errors
# Maybe use shelve module in future version to keep a history of NN tweets

# Setting up blanks here (a) prevents erroring out, and (b) allows for a test below

tweetList = []
dateStamp = ''

# Iterate in reverse chron order through scrobbles to create a list of (for this session) uniques

for i in reversed(range(trackListLen)): 
	currentTrack = trackList[i]
	currentAlbum = currentTrack['album']['#text']
	currentArtist = currentTrack['artist']['#text']
	currentName = currentTrack['name']
	currentURL = currentTrack['url']
	dateStamp = currentTrack['date']['uts'] #this already shows as a string, so no need to convert
	nowPlaying = ('#nowplaying ' + currentArtist + ' – \"' + currentName + '\" from \"' + currentAlbum + '\"' + ' ' + currentURL)
	if nowPlaying not in tweetList:
		tweetList.append(nowPlaying) 

# Then run through the list in the new order -- it's now chronologically ordered
	
for i in range(len(tweetList)):
	try:
		status = api.PostUpdate(tweetList[i])
		print("{0} just posted: {1}".format(status.user.name, status.text))
		#print(tweetList[i])
	except:
		tweetErrFile = open(tweetErrFileLoc, 'a')
		tweetErrFile.write(tweetList[i])
		tweetErrFile.close()
	time.sleep(120) 
	# I was running 1 minute intervals to get through the first block of scrobbles, and Twitter assumed it was spam after about 40
	# Could have been extenuating circumstances, but two minutes seems to work. 

# Stash the last scrobble datestamp (using the blank dateStamp to avoid blanking the file datestamp if there's no scrobbles)

if dateStamp:
	lastScrobbleFile = open(lastScrobbleFileLoc, 'w')
	lastScrobbleFile.write(dateStamp)
	lastScrobbleFile.close()