Skip to content
Browse files

Initial import

  • Loading branch information...
0 parents commit 1900762819a3f24a89dd9dbc5878844dacc33bc7 @alastair committed
Showing with 225 additions and 0 deletions.
  1. +25 −0 README
  2. +32 −0 bestsongs.sh
  3. +71 −0 selectsongs
  4. +93 −0 song2m3u
  5. +4 −0 song2m3u.sh
25 README
@@ -0,0 +1,25 @@
+best.m3u
+========
+
+Best genererates a playlist of your music collection based on the
+top two tracks of each artist in your collection. The top tracks
+are chosen using last.fm's popularity lists.
+
+To run
+======
+bestsongs.sh /path/to/music
+selectsongs > best.txt
+song2m3u.sh /path/to/music
+
+To do
+=====
+Scripts expect music to be in directories named 'Artist - year - Album'
+and files named 'track - Artist - Name'
+Use last.fm's api to search for an artist in the case that a match
+can't be found
+XML parsing needs to be updated to work with python 2.5
+
+Authors
+=======
+Perry Lorrier - http://github.com/isomer/
+Alastair Porter http://github.com/alastair/
32 bestsongs.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+pw=$(pwd)
+if [ ! -d "$pw/data" ]; then
+ mkdir "$pw/data"
+fi
+
+pushd $1
+for f in $(ls |
+ sed -e 's/ - .*//g' -e 's/ /+/g' |
+ uniq ); do
+ if [ ! -f "$pw/data/$f" ]; then
+ wget -U "Best Songs" "http://ws.audioscrobbler.com/1.0/artist/$f/toptracks.xml" -O "$pw/data/$f"
+ sleep 2
+ fi
+ done
+popd
+
+echo Building best songs
+(cd data ; ls ) | while read i
+do
+ grep '<name>' "data/$i" |
+ head -n 2 |
+ while read song
+ do
+ echo $i:$song
+ done
+done | sed -e 's@</name>@@g' \
+ -e 's@<name>@@g' \
+ -e 's@+@ @g' \
+ -e 's/&amp;/\&/g' >best.txt
+
71 selectsongs
@@ -0,0 +1,71 @@
+#!/usr/bin/python
+import os
+import xml.dom.ext.reader.Sax2
+import sys
+
+alldata={}
+
+def fix(x):
+ try:
+ return unicode(x)
+ except:
+ #print `x`,unicode(x,"utf8").encode("ascii","replace")
+ return unicode(x,"utf8")
+
+for i in os.listdir("data"):
+ if i.startswith("."):
+ continue
+
+ # only process the first 5 for speed while testing
+# if len(alldata.keys())>5:
+# break
+
+ # create Reader object
+ reader = xml.dom.ext.reader.Sax2.Reader()
+
+ # parse the document
+ try:
+ doc = reader.fromStream(open(os.path.join("data",i)))
+ except xml.sax._exceptions.SAXParseException:
+ print >>sys.stderr,"*** failed to parse",i
+ continue
+ alldata[fix(i)]=[]
+ print >>sys.stderr,i
+ for j in doc.lastChild.childNodes:
+ if j.nodeType == 3: # text node
+ continue
+ data={}
+ for k in j.childNodes:
+ if k.nodeType == 3: # text node
+ continue
+ if k.childNodes:
+ if k.nodeName=="reach":
+ data[k.nodeName]=int(k.firstChild.data)
+ else:
+ data[k.nodeName]=k.firstChild.data
+ x=alldata[fix(i)]
+ x.append(data)
+ alldata[fix(i)]=x
+
+results=[]
+songs={}
+for i in alldata:
+ songs[i]=2
+ scores=[(x["reach"],x["name"]) for x in alldata[i]]
+ scores.sort()
+ results=results+[u"%s : %s" % (i,x[1]) for x in scores[:2]]
+
+while len(results)<3000:
+ x=[(float(z["reach"])/songs[y],y,z["name"]) for y in alldata for z in alldata[y] ]
+ x.sort()
+ x.reverse()
+ while x!=[] and (u"%s : %s" % (x[0][1],x[0][2]) in results):
+ x.pop(0)
+ if x==[]:
+ print >>sys.stderr,"Not enough data",len(results)
+ break
+ results.append(u"%s : %s" % (x[0][1],x[0][2]))
+ songs[x[0][1]]=songs[x[0][1]]+1
+
+for i in results:
+ print i.encode("utf8")
93 song2m3u
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+import sys
+import os
+import fnmatch
+import random
+import sre
+
+debug=0
+
+preferences=r"+greatest hits:+best of:-\<live:-remix:-mix:+collection:-\("
+
+preferences=[x.lower() for x in preferences.split(":")]
+
+BETTER_THAN=-1
+WORSE_THAN=1
+
+def compare(a,b,debug=0):
+ for i in preferences:
+ flag,name = i[0],i[1:]
+ aok = (sre.search(name,a.lower()) is not None)
+ bok = (sre.search(name,b.lower()) is not None)
+ if aok == bok:
+ if debug>1: print >>sys.stderr,"",`a`,"incompariable to",`b`,"because of",flag,`name`
+ continue
+ if aok and not bok:
+ if flag=="+":
+ if debug: print >>sys.stderr,"",a,"better than",b,"because of",flag,`name`
+ return BETTER_THAN
+ else:
+ if debug: print >>sys.stderr,"",b,"better than",a,"because of",flag,`name`
+ return WORSE_THAN
+ if not aok and bok:
+ if flag=="-":
+ if debug: print >>sys.stderr,"",a,"better than",b,"because of",flag,`name`
+ return BETTER_THAN
+ else:
+ if debug: print >>sys.stderr,"",b,"better than",a,"because of",flag,`name`
+ return WORSE_THAN
+ c = cmp(a.lower(),b.lower())
+ if c!=0:
+ if debug:
+ if c<0:
+ print >>sys.stderr,"",`a.lower()`,"asciibetically earlier than",`b.lower()`
+ elif c>0:
+ print >>sys.stderr,"",`a.lower()`,"asciibetically later than",`b.lower()`
+ return c
+ c = cmp(a,b)
+ if debug:
+ if c<0:
+ print >>sys.stderr,"",`a`,"asciibetically earlier than",`b`
+ elif c>0:
+ print >>sys.stderr,"",`a`,"asciibetically later than",`b`
+ else:
+ print >>sys.stderr,"",`a`,"asciibetically equal to",`b`
+ return c
+
+def fix(x):
+ return x \
+ .replace(".","*") \
+ .replace(",","*") \
+ .replace("?","*") \
+ .replace("+","*") \
+ .replace("'","*").lower()
+
+def fixartist(x):
+ return x.replace("+","*")
+
+albums=os.listdir(sys.argv[1])
+for i in sys.argv[2:]:
+ for j in open(i,"r"):
+ aname,s=j.strip().split(":",1)
+ aname = fixartist(aname)
+ a=[
+ os.path.join(sys.argv[1],x)
+ for x in albums
+ if fnmatch.fnmatch(x.lower(),"*"+aname.lower()+"*")]
+ a=reduce(lambda a,b:a+b,[[(x,y) for y in os.listdir(x)] for x in a],[])
+ a=[
+ os.path.join(x,y)
+ for x,y in a
+ if fnmatch.fnmatch(y.lower(),"*-*-*"+fix(s)+"*.mp3")
+ ]
+ if a==[]:
+ print >>sys.stderr,aname,":",s,":","Not found"
+ else:
+ a.sort(compare)
+ if len(a)>1:
+ print >>sys.stderr,aname,":",s,":","multiples. preferences:"
+ old=a[0]
+ for k in a[1:]:
+ compare(old,k,debug=1)
+ old=k
+ print a[0]
4 song2m3u.sh
@@ -0,0 +1,4 @@
+
+./song2m3u "$1" best.txt >best.m3u 2>best.err
+
+sed -e '/Not found/!d' -e 's/: Not found.*//' < best.err >missing

0 comments on commit 1900762

Please sign in to comment.
Something went wrong with that request. Please try again.