ocarina/libsaria/sources/library.py
Bryan Schumaker f063da5b56 Began work on virtual sources
Virtual sources should make it easier to do things with the current song
without having to know anything about it (such as a song id or file
path).
2010-12-05 17:11:41 -05:00

309 lines
5.7 KiB
Python

# Bryan Schumaker (11/05/2010)
import libsaria
import libsaria.sources
import libsaria.path.files
from libsaria import threads
splitext = libsaria.path.splitext
os = None
tagpy = None
Track = None
FileRef = None
fs_tree = None
tag_tree = None
index = None
tracks = None
locations = None
size = None
visible = None
source = None
cur_id = -1
lib_lock = threads.get_mutex("library")
loaded = False
filtered = False
badfiles = set()
def init():
global source
import string
ttable = dict()
for s in string.punctuation:
ttable[ord(s)] = u""
for s in string.lowercase:
ttable[ord(s)] = ord(s) - 32
source = libsaria.sources.Source("library")
source.get_attrs = get_attrs
def reset():
from libsaria.trees import FSTree, DLFSTree, DLValTree
from index import Index
global index
global tracks
global fs_tree
global tag_tree
global locations
global visible
locations = []
fs_tree = DLFSTree()
tag_tree = DLValTree()
index = Index()
tracks = dict()
size = 0
visible = set()
def load():
global fs_tree
global tag_tree
global index
global tracks
global locations
global lib_lock
global loaded
objects = libsaria.path.files.load("library", ".lib")
if objects == None or len(objects) != 5:
reset()
else:
(locations, tracks, fs_tree, tag_tree, index) = objects
lib_lock.acquire()
loaded = True
lib_lock.release()
libsaria.event.start("POSTLIBLOAD")
def is_loaded():
lib_lock.acquire()
val = loaded
lib_lock.release()
return val
def init_bg2(callback):
init()
load()
callback()
def init_bg(callback):
thr = threads.BG_Thread(init_bg2, callback)
thr.start()
def save():
global sources
libsaria.path.files.save( (locations, tracks, fs_tree, tag_tree, index),
"library", ".lib")
def walk():
for tag in tag_tree.walk():
yield tag[3]
def get_locations():
for loc in locations:
yield loc
def artists():
keys = tag_tree.keys()
keys.sort()
res = []
for key in keys:
res.append( (tag_tree[key].value, key) )
return res
def albums(artist):
art = tag_tree[artist]
keys = art.keys()
keys.sort()
res = []
for key in keys:
res.append( (art[key].value, key) )
return res
def titles(artist, album):
art = tag_tree[artist]
alb = art[album]
keys = alb.keys()
keys.sort()
res = []
for key in keys:
res.append( (alb[key].value, key) )
return res
def song_id(artist, album, title):
art = tag_tree[artist]
alb = art[album]
title = alb[title]
return title.keys()[0]
def get_attrs(*attrs):
if attrs[0].__class__ != str:
id = attrs[0]
attrs = attrs[1:]
else:
id = cur_id
res = []
rec = tracks.get(id, None)
if rec == None:
return [0] * len(attrs)
get = rec.__dict__.get
tags = rec.tags.walk_vals_backwards()
for attr in attrs:
if attr == "id":
res += [id]
elif attr == "filepath":
res += [rec.fs.walk_path_backwards()]
elif attr == "art":
from libsaria import lastfm
res += [lastfm.get_artwork_id(id)]
elif attr == "artist":
res += [tags[0]]
elif attr == "album":
res += [tags[1]]
elif attr == "title":
res += [tags[2]]
else:
res += [get(attr, None)]
if len(res) == 1:
return res[0]
return res
def set_attr(id, attr, new_value):
rec = tracks.get(id, None)
if rec:
if attr == "art":
from libsaria import lastfm
artist, album = get_attrs(id, "artist", "album")
lastfm.set_artwork_tags(artist, album, new_value)
else:
rec.__dict__[attr] = new_value
def change_score():
prcnt = libsaria.audio.get_progress()
if prcnt > 0.75:
inc_count(cur_id)
inc_score(cur_id)
if prcnt < 0.33:
inc_score(cur_id, -1)
def inc_score(id = cur_id, amount=1):
rec = tracks.get(id, None)
if rec:
rec.score += amount
save()
def inc_count(id = cur_id):
rec = tracks.get(id, None)
if rec:
rec.count += 1
save()
def play_id(id):
if load_id(id) == True:
libsaria.controls.play()
return True
return False
def load_id(id):
global cur_id
if tracks.get(id, None) == None:
return False
cur_id = id
return source.load_file(get_attrs(id, "filepath"))
def filter(text):
global visible
global index
global filtered
if len(text) > 0:
visible = index.filter(text)
filtered = True
else:
visible = None
filtered = False
def test_filter(text):
return index.filter(text)
def is_visible(id):
global filtered
global visible
if filtered == False:
return True
else:
return id in visible
def add_location(path):
global locations
if path.__class__ == unicode:
path = str(path)
if path not in locations:
locations.append(path)
def scan(path):
add_location(path)
update()
save()
def insert_track(path, ref):
global tracks
global ttable
global fs_tree
global tag_tree
global index
tags = ref.tag()
audio = ref.audioProperties()
ino = os.stat(path).st_ino
track = Track(tags, audio)
artist = tags.artist or u"Unknown Artist"
album = tags.album or u"Unknown Album"
title = tags.title or u"Unknown Title"
fs = fs_tree.insert_path(path)
tag = tag_tree.insert( [artist.translate(ttable),
album.translate(ttable),
title.translate(ttable), ino],
[artist, album, title, ino]
)
index.insert(ino, (artist, album, title))
track.fs = fs
track.tags = tag
tracks[ino] = track
def update_path(path):
global badfiles
tree = libsaria.path.make_tree(path)
for path in tree.walk_paths():
ext = splitext(path)[1]
if ext in badfiles:
continue
try:
ref = FileRef(path)
except Exception, e:
badfiles.add(ext)
print e
continue
try:
insert_track(path, ref)
except Exception, e:
print e
def update():
global os
global tagpy
global FileRef
global Track
import os
import tagpy
from track import Track
FileRef = tagpy.FileRef
sep = libsaria.path.sep
for path in locations:
update_path(path)