From adcb73dac9da740d3ea7554bd2a7f5089cfbc6e5 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Wed, 6 Oct 2010 23:31:36 -0400 Subject: [PATCH] Have a working doubly-linked tree based library. I have a bit more to do before I support everything the old library did. Mostly getattr work. --- libsaria/collection/__init__.py | 17 ++- libsaria/collection/collection.py | 148 ++++++-------------- libsaria/collection/{filters.py => lens.py} | 8 +- libsaria/collection/tree.py | 112 +++++---------- ocarina/collection.py | 12 +- ocarina/entry.py | 5 + ocarina/info.py | 1 - tests/collection.py | 4 +- tests/dl_tree.py | 4 +- 9 files changed, 106 insertions(+), 205 deletions(-) rename libsaria/collection/{filters.py => lens.py} (82%) diff --git a/libsaria/collection/__init__.py b/libsaria/collection/__init__.py index 6961dfe7..e2ecd7c6 100644 --- a/libsaria/collection/__init__.py +++ b/libsaria/collection/__init__.py @@ -13,11 +13,8 @@ LIBRARY = 0 PLAYLIST = 1 QUEUE = 2 -import collection -library = collection.Collection() - -import filters -library2 = filters.Library() +import lens +library2 = lens.Library() cur_lib_id = -1 @@ -33,6 +30,7 @@ def new_source2(path, bg=True): path = expand(path) if not exists(path): return 0 + library2.reset() return call("NEWSOURCE2", library2.scan, path) def walk_library(): @@ -40,10 +38,15 @@ def walk_library(): for track in library: yield track +def scan_library(): + global library2 + for track in library2.walk_tags(): + yield track + def lib_get_attr(id, attr): - global library + global library2 if id >= 0: - return library.get_attr(id, attr) + return library2.get_attr(id, attr) return None def lib_play_id(id): diff --git a/libsaria/collection/collection.py b/libsaria/collection/collection.py index 9f87339b..7c5e69cf 100644 --- a/libsaria/collection/collection.py +++ b/libsaria/collection/collection.py @@ -8,98 +8,11 @@ ins_table = None ins_index = None ins_tree = None -class Collection: - def __init__(self): - self.tree = None - - def __iter__(self): - if not self.tree: - self.load() - for track in self.tree.walk(): - yield track - - def get_attr(self, id, attr): - node = self.tree - tags = self.table[id] - for tag in tags: - node = node[tag] - return node[attr] - - def scan(self, path): - print "Scanning path:", path - global ins_table - global ins_index - global ins_tree - self.reset() - ins_table = self.table.insert - ins_index = self.index.insert - ins_tree = self.tree. insert - self.update(path) - self.save() - - def reset(self): - print "Resetting collection ... " - from table import Table - from index import Index - from tree import Tree - self.table = Table() - self.index = Index() - self.tree = Tree() - - def save(self): - from libsaria import data - data.save((self.table, self.index, self.tree), "library", "") - - def load(self): - from libsaria import data - objects = data.load("library", "") - if objects == None: - self.reset() - return - (self.table, self.index, self.tree) = objects - - def insert(self, file, filepath): - global tag - global audio - global ins_table - global ins_index - global ins_tree - tags = tag(file) - audio_prop = audio(file) - if tags.artist == u"": - tags.artist = "Unknown Artist" - if tags.album == u"": - tags.album = "Unknown Album" - if tags.title == u"": - tags.title = "Unknown Title" - list = [tags.artist, tags.album, tags.title] - id = ins_table(list) - ins_index(id, list) - list.append(id) - ins_tree(list, tags, audio_prop, filepath) - - def update(self, path): - global tag - global audio - FileRef = libsaria.collection.FileRef - join = libsaria.path.join - insert = self.insert - tag = FileRef.tag - audio = FileRef.audioProperties - - for root,dirs,files in libsaria.path.walk(path): - for file in files: - file = join(root,file) - try: - insert(FileRef(file), file) - except Exception,e: - pass - class TrackRecord: def __init__(self, year, length): - self.length = 0 + self.length = length self.count = 0 - self.year = 0 + self.year = year #self.like = None self.fs = None @@ -107,22 +20,31 @@ class TrackRecord: class Collection2: - def __init__(self): - self.fs_tree = None - self.tag_tree = None - self.records = None - self.next_record = 0 + def __init__(self, file): + self.file = file + self.load() - def save(self, file): + def save(self): libsaria.data.save( - [self.fs_tree, self.tag_tree, self.records, self.next_record], - file, "") + [self.fs_tree, self.tag_tree, self.records, + self.next_record, self.size], + self.file, "") + + def load(self): + objects = libsaria.data.load(self.file, "") + if objects == None or len(objects) != 5: + self.reset() + return + (self.fs_tree, self.tag_tree, self.records, + self.next_record, self.size) = objects def reset(self): from tree import DLTree - self.fs_tree = DLTree() - self.tag_tree = DLTree() - self.records = dict() + self.fs_tree = DLTree() + self.tag_tree = DLTree() + self.records = dict() + self.next_record = 0 + self.size = 0 def disp(self): pass @@ -131,18 +53,31 @@ class Collection2: #print #self.tag_tree.disp() + def walk_tags(self): + for tag in self.tag_tree.walk_forwards(): + rec = self.records[tag[3]] + yield tag + [rec.year] + [rec.length] + + def get_attr(self, id, attr): + rec = self.records[id] + if attr == "filepath": + cmp = rec.fs.walk_backwards() + return libsaria.path.sep.join([""] + cmp) + if attr == "playcount": + return rec.count + def insert_allocate(self, components, ref): t = ref.tag() - artist = str(t.artist) - album = str(t.album) - title = str(t.title) + artist = t.artist + album = t.album + title = t.title audio = ref.audioProperties() if artist == "": - artist = "Unknown Artist" + artist = u"Unknown Artist" if album == "": - album = "Unknown Album" + album = u"Unknown Album" if title == "": - title = "Unknown Title" + title = u"Unknown Title" record = TrackRecord(t.year, audio.length) @@ -155,3 +90,4 @@ class Collection2: record.fs = fs record.tags = tags self.records[id] = record + self.size += 1 diff --git a/libsaria/collection/filters.py b/libsaria/collection/lens.py similarity index 82% rename from libsaria/collection/filters.py rename to libsaria/collection/lens.py index b7a80a40..471c0216 100644 --- a/libsaria/collection/filters.py +++ b/libsaria/collection/lens.py @@ -12,19 +12,15 @@ splitext = libsaria.path.splitext class Library(collection.Collection2): def __init__(self): - collection.Collection2.__init__(self) + collection.Collection2.__init__(self, "DLTree_test") self.badfiles = set() pass - #def save(self): - #libsaria.data.save((self.fs_tree, self.tag_tree), "DLTree_test", "") - # libsaria.data.save(self, "DLTree_test", "") - def scan(self, path): print "Library scanning %s" % path self.reset() self.update(path) - self.save("DLTree_test") + self.save() self.disp() def update(self, path): diff --git a/libsaria/collection/tree.py b/libsaria/collection/tree.py index 82371e4a..a83cbd23 100644 --- a/libsaria/collection/tree.py +++ b/libsaria/collection/tree.py @@ -1,70 +1,12 @@ # Bryan Schumaker (8 / 12 / 2010) -get = dict.get - -class TagNode(dict): - def __init__(self, id): - dict.__init__(self) - self["id"] = id - - def insert(self, tag_list, tags, audio, filepath): - self["artist"] = tags.artist - self["album"] = tags.album - self["title"] = tags.title - self["year"] = tags.year - - self["filepath"] = filepath - self["playcount"] = 0 - - length = audio.length - sf = 0 - sec = length % 60 - if sec >= 10: - sf = "" - min = (length - sec) / 60 - mf = 0 - if min >= 10: - mf = "" - - self["seconds"] = audio.length - self["length"] = "%s%s:%s%s" % (mf, min, sf, sec) - - def walk(self): - yield self - - -class Tree(dict): - def __init__(self): - dict.__init__(self) - - def walk(self): - keys = self.keys() - keys.sort() - get_item = self.__getitem__ - for key in keys: - for track in get_item(key).walk(): - yield track - - def insert(self, tag_list, tags, audio, filepath): - if len(tag_list) == 0: - return - global get - global insert - tag = tag_list[0] - node = get(self, tag, None) - if node == None: - if len(tag_list) == 1: - node = TagNode(tag) - else: - node = Tree() - self[tag] = node - node.insert(tag_list[1:], tags, audio, filepath) - +classes = set([str, int, unicode]) class DLTree: def __init__(self, parent=None): self.parent = parent - self.children = None + self.child_fwd = dict() + self.child_bck = dict() def disp(self, level=0): space = " " * level @@ -77,38 +19,58 @@ class DLTree: keys.sort() for key in keys: - if key.__class__ == str or key.__class__ == int: - value = children[key] - print space, key - value.disp(level+1) + if key.__class__ in classes:#== str or key.__class__ == int or key.__class__ == unicode: + #value = children[key] + yield key + #value.disp(level+1) #if len(self.children) == 0: # print self.get_path() - def get_path(self, child=None): + def walk_backwards(self, child=None): if self.parent == None: - return [self.children[child]] - cmp = self.children.get(child, None) + return [self.child_bck[child]] + cmp = self.child_bck.get(child, None) child = self - path = self.parent.get_path(child) + path = self.parent.walk_backwards(child) if cmp != None: path.append(cmp) return path + def walk_forwards(self): + children = self.child_fwd + + keys = children.keys() + keys.sort() + + for key in keys: + child = children[key] + has_children = False + for result in child.walk_forwards(): + has_children = True + res = [key] + if result != None: + res += result + yield res + # A leaf will have no children, but + # still needs to yield a value + if has_children == False: + yield [key] + def insert(self, path): cmp = path[0] child = None try: - child = self.children[cmp] + child = self.child_fwd[cmp] except TypeError: - self.children = dict() + #self.children = dict() child = DLTree(self) - self.children[cmp] = child - self.children[child] = cmp + self.child_fwd[cmp] = child + self.child_bck[child] = cmp except KeyError: child = DLTree(self) - self.children[cmp] = child - self.children[child] = cmp + self.child_fwd[cmp] = child + self.child_bck[child] = cmp if len(path) > 1: return child.insert(path[1:]) return self diff --git a/ocarina/collection.py b/ocarina/collection.py index fab81fb7..641aec68 100644 --- a/ocarina/collection.py +++ b/ocarina/collection.py @@ -30,13 +30,8 @@ class Collection(gtk.ScrolledWindow): insert = self.list.list.insert ins_next = 0 for track in func(): - get = track.__getitem__ - insert(ins_next, [get("id"), - get("title"), - get("length"), - get("artist"), - get("album"), - get("year"), ""]) + insert(ins_next, [track[3], track[2], + track[5], track[0], track[1], track[4], ""]) ins_next += 1 self.list.thaw() @@ -67,7 +62,8 @@ class Library(Collection): def populate(self): import datetime before = datetime.datetime.now() - Collection.populate(self, collection.walk_library) + #Collection.populate(self, collection.walk_library) + Collection.populate(self, collection.scan_library) after = datetime.datetime.now() print "Populating took: %s" % (after-before) diff --git a/ocarina/entry.py b/ocarina/entry.py index 684dc8d7..e2b70595 100644 --- a/ocarina/entry.py +++ b/ocarina/entry.py @@ -6,4 +6,9 @@ gtk = ocarina.gtk class FilterEntry(gtk.Entry): def __init__(self): gtk.Entry.__init__(self) + self.connect("changed", self.changed) self.show() + + def changed(self, entry): + # We want to start filtering here + print entry.get_text() diff --git a/ocarina/info.py b/ocarina/info.py index 74dc9aef..b13618ce 100644 --- a/ocarina/info.py +++ b/ocarina/info.py @@ -36,7 +36,6 @@ class FilterBar(Bar): Bar.__init__(self, False) global button global entry - #global libsaria self.pack(entry.FilterEntry(), True, True) self.pack(button.OpenButton()) diff --git a/tests/collection.py b/tests/collection.py index 998a223e..a4590210 100644 --- a/tests/collection.py +++ b/tests/collection.py @@ -2,9 +2,11 @@ from libsaria import collection -src = "~/Music" +#src = "~/Music" #src = "~/Music/Foo Fighters" #src = "~/Music/Foo Fighters/Foo Fighters" +src = "/media/Music" + collection.new_source(src, bg=False) #print collection.source.index diff --git a/tests/dl_tree.py b/tests/dl_tree.py index 956c555c..0279f8a8 100644 --- a/tests/dl_tree.py +++ b/tests/dl_tree.py @@ -4,4 +4,6 @@ from libsaria import collection -collection.new_source2("~/Music/") +#collection.new_source2("~/Music/") +collection.new_source2("/media/Music") +print collection.library2.size