Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: alastair/scrobbyl
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: cincodenada/scrobbyl
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Jan 15, 2012

  1. Copy the full SHA
    8013e6b View commit details

Commits on Apr 16, 2012

  1. Reorganizing things some more, making scrobbyl.py a master that

    calls functions from elsewhere to make an actually useful loop
    cincodenada committed Apr 16, 2012
    Copy the full SHA
    00dd5c6 View commit details
  2. Updating the readme

    cincodenada committed Apr 16, 2012
    Copy the full SHA
    2b8e89b View commit details
Showing with 163 additions and 94 deletions.
  1. +31 −0 README.md
  2. +3 −2 fp.py
  3. +33 −33 recorder.py
  4. +96 −59 scrobbyl.py
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
Scrobbyl
==========================

This is a fork of the original Scrobbyl, because I tried to get it to work and couldn't.

It's certainly incomplete, and I've had trouble getting it to recognize songs recorded
from a microphone due to the fingerprinting not recgonizing it, which isn't something
that can really be adjusted for on the client side, so no guarantees there. Do let me
know if you have success with that though.

You'll need at least the following Python packages to run this. Use whatever package manager you
prefer, I uses `pip`, so I run `pip install <packagename>`:

* pyechonest
* pyaudio

If you run `python scrobbyl.py` (after running the lastfm auth detailed below), the script
will run a loop of recording a sample, trying to identify it. If it recognizes a song
that it hasn't scrobbled, it will scrobble said song. The length recorded defaults to
20 seconds, you can change that in `scrobbyl.py` in the call to recorder.recordAudio.

This hasn't been extensively tested, I just threw my latest stuff up here because someone
e-mailed me asking about it. But in any case, it should work better than the original
stuff, which was quite broken by now. It at least runs in a loop, takes in audio,
and tries to recognize it and scrobble it.

I have ambitions to make a GUI out of it and such, but honestly there are more
important/interesting things on my plate at the moment, so I make no promises.

If you have questions/comments, just leave comments here or otherwise contact me via GitHub.

Original Readme
==========================

Don't you wish you could **scrobb**le your vin**yl**? Well, now you can.

What it does
5 changes: 3 additions & 2 deletions fp.py
Original file line number Diff line number Diff line change
@@ -4,10 +4,11 @@
import subprocess
import wave
import tempfile
import pycodegen
import struct
import json
import sys
import pyechonest.song as song
import pyechonest.config as config

supported_types = [".mp3", ".ogg", ".flac"]

@@ -38,7 +39,7 @@ def fingerprint(file):
fs.append(struct.unpack("<h", frames[i:i+2])[0]/MAGIC)

#print "num samples", len(fs)
cg = pycodegen.pycodegen(fs, 10)
cg = song.util.codegen(fs)
return cg.getCodeString()

finally:
66 changes: 33 additions & 33 deletions recorder.py
Original file line number Diff line number Diff line change
@@ -8,36 +8,36 @@
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5

p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
output = True,
frames_per_buffer = chunk)

print "* recording"
all = []
for i in range(0, 44100 / chunk * RECORD_SECONDS):
data = stream.read(chunk)
all.append(data)
# check for silence here by comparing the level with 0 (or some threshold) for
# the contents of data.
# then write data or not to a file

print "* done"

stream.stop_stream()
stream.close()
p.terminate()

data = ''.join(all)
wf = wave.open("recorded.wav", 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(data)
wf.close()

def recordAudio(tofile, seconds):
p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
output = True,
frames_per_buffer = chunk)

print "* recording"
all = []
for i in range(0, 44100 / chunk * seconds):
data = stream.read(chunk)
all.append(data)
# check for silence here by comparing the level with 0 (or some threshold) for
# the contents of data.
# then write data or not to a file

print "* done"

stream.stop_stream()
stream.close()
p.terminate()

data = ''.join(all)
wf = wave.open(tofile, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(data)
wf.close()
155 changes: 96 additions & 59 deletions scrobbyl.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,106 @@
#!/usr/bin/env python

import ConfigParser
import pprint
import sys
import os
import subprocess
import json
import echonest
import time
import pyechonest.config as config
import pyechonest.song as song
from fp import fingerprint
import lastfm
import recorder

def fingerprint(file):
platform = os.uname()[0]
if platform == "Darwin":
codegen = "./ext/codegen.Darwin"
path = ".:"+os.getenv("PATH")
elif platform == "Linux":
codegen = "./ext/codegen.Linux-i686"
path = os.getenv("PATH")
proclist = [codegen, os.path.abspath(file), "0", "20"]
p = subprocess.Popen(proclist, env={"PATH":path}, stdout=subprocess.PIPE)
code = p.communicate()[0]
return json.loads(code)

def main(file):
statusfile = os.path.expanduser("~/.scrobbyl")
lines = []
if os.path.exists(statusfile):
fp = open(statusfile, "r")
lines = fp.readlines()
fp.close()
lasttime = 0
lastartist = ""
lasttrack = ""
if len(lines) == 3:
lasttime = int(lines[0])
lastartist = lines[1]
lasttrack = lines[2]

f = fingerprint(file)

code = f[0]["code"]
song = echonest.fp_lookup(code)
echonest.pp(song)

if "response" in song and "status" in song["response"] \
and song["response"]["status"]["message"] == "Success" \
and len(song["response"]["songs"]) > 0:

track = song["response"]["songs"][0]["title"]
artist = song["response"]["songs"][0]["artist_name"]
now = time.time()

print (now-lasttime)
if now - lasttime < 100:
# Only scrobble if we've just been playing
if lasttrack != "" and lasttrack != track:
print "Last track was",lasttrack,"now",track,", scrobbling"
else:
print "same song"
else:
print "too long since we last did it,", now-lasttime
fp = open(statusfile, "w")
fp.write("%d\n%s\n%s" % (now, artist, track))
fp.close()
config.ECHO_NEST_API_KEY="F4LP3UJVBPYSPVKRZ"

def main():
platform = os.uname()[0]
if platform == "Darwin":
codegen = "./ext/codegen.Darwin"
path = ".:"+os.getenv("PATH")
elif platform == "Linux":
codegen = "./ext/codegen.Linux-i686"
path = os.getenv("PATH")
config.CODEGEN_BINARY_OVERRIDE = os.path.abspath(codegen)

while(True):
recorder.recordAudio("recorded.wav",20)
try:
scrobbled = tagSong("recorded.wav")
except Exception:
pass

def tagSong(filename):
#Get status info
statusfile = os.path.expanduser("~/.scrobbyl")
lines = []

if os.path.exists(statusfile):
fp = open(statusfile, "r")
lines = fp.readlines()
fp.close()
lasttime = 0
lastartist = ""
lasttrack = ""
lastscrobble = 0
if len(lines) == 4:
lasttime = int(lines[0])
lastartist = lines[1].strip()
lasttrack = lines[2].strip()
lastscrobble = int(lines[3])



fp = song.util.codegen(filename)
pprint.pprint(fp)

#Make sure we have a valid fp
if fp == None or len(fp) == 0 or "code" not in fp[0]:
raise Exception("Could not calculate fingerprint!")

result = song.identify(query_obj=fp, version="4.11",buckets="audio_summary")
pprint.pprint(result)

if len(result) == 0:
raise Exception("Song not found in database.")

track = result[0].title
artist = result[0].artist_name
songlength = result[0].audio_summary.duration

#Check to make sure it's not a duplicate
now = time.time()
doscrobble = True
if lasttime:
if (now - lasttime) < 100:
#Check for duplicate song
if lasttrack == track and lastartist == artist:
#if config.getboolean('scrobble_rules','allow_repeat') and prevlength < (now - config.get('runtime_info','last_scrobble')):
if False:
print "Same song, but looks like it repeated..."
else:
print "Same song as last time, skipping..."
doscrobble = False
else:
print "New song!"
else:
print "It's been longer than the songlength since we last checked."
else:
lasttrack = lastartist = "none"
print "No previous song found."

if(doscrobble):
print "Last track was %s by %s, now %s by %s. Scrobbling..." % (lasttrack, lastartist, track, artist)
#lastfm.scrobble(artist, track)
lastscrobble = now

fp = open(statusfile, "w")
fp.write("%d\n%s\n%s\n%d" % (now, artist, track, lastscrobble))
fp.close()

return (track, artist, doscrobble)

if __name__=="__main__":
if len(sys.argv) < 2:
print >>sys.stderr, "usage: %s <file>" % sys.argv[0]
sys.exit(0)
main(sys.argv[1])
main()