Collections Python - nesciens/xmms2-wiki GitHub Wiki
There are a number of options, some of them are:
All python examples use Sync API for simplicity
create a collections class which represents the various collections semantics as properties and attributes (with the occasional method if necessary).
A few examples:
Get an id list from a collection and set it to the id list of a new collection.
coll_foo = xc.Collection('Foo')
ids = coll_foo.ids
idl_coll = xc.Collection(XMMS_COLL_TYPE_IDLIST)
idl_coll.ids = ids
create a union of collection "Foo" and a custom collection (all media by Sonic Youth), and filter the resulting collection by year (only media from 2006).
coll = xc.Collection(XMMS_COLL_TYPE_AND);
# Reference to collection 'Foo'
operand = xc.Connection(XMMS_COLL_TYPE_REFERENCE);
operand['reference'] = ('Foo', 'Collections')
coll.operand.append(operand)
# All media by Sonic Youth
operand = xc.Collection(XMMS_COLL_TYPE_MATCH);
allmedia = xc.Collection(XMMS_COLL_TYPE_UNIVERSE)
operand.operand.append(allmedia)
operand['field'] = 'artist'
operand['value'] = 'Sonic Youth'
coll.operand.append(operand)
# Filter media on year 2006
last = xc.Collection(XMMS_COLL_TYPE_MATCH);
last['year'] = '2006'
last.operand.append(coll)
Create a collections class with the same get/set methods as in the c bindings.
Lets cut to the examples directly:
from xmmsclient import collections as c
coll = c.And(c.Reference('Collections:Foo'),
c.Match(c.Universe(), {'field': 'artist', 'value': 'Sonic Youth'}),
c.Match(c.Universe(), {'field': 'year', 'value': '2006'}))
How to use and modify them!
print coll.operands
# [
,
,
]
del coll.operands[0]
coll.operands.append(c.Reference('Collections:Party music'))
print coll.operands
# [
,
,
]
# make it persistant on server!
xc.coll_save(coll, 'Collections', 'My collection')
m = c.Match(c.Universe(), {'field': 'artist', 'value': 'Thievery Corporation'})
# get a list of ids matching collection
matchingids = xc.coll_query_id(m)
# I changed my mind..
m['value'] = 'Air'
songsbyair = xc.coll_query_info(m, ['title', 'duration', 'rating'])
for song in songsbyair:
print "%(album)s - %(title)s (%(duration)s)" % song
Let's start with a pseudo-class-def
class SomeOp (Collection):
def __init__(self, *based_on, **arguments)
def __getitem__(self, name)
def __setitem__(self, name, val)
def get_data(self)
def set_data(self, data)
def get_bases(self) # these three might need better names
def set_bases(self, based_on)
def add_bases(self, *based_on)
and examples:
base = c.Reference(name="SomeColl") # **arguments for name, *based_on nothing
jovibon = c.Match(base, field="artist", value="Jovi, Bun") # *based_on = [base]
bonjovi = c.Match() # we can add stuff later
bonjovi.set_bases([base]) # like... here or in the next line.
bonjovi.set_data({'field': 'artist', 'value': 'Bon Jovi'})
alljovi = c.Or(jovibon, bonjovi)
cool = c.And(alljovi) # This time, set half the data later.
cool.add_bases(c.Not(c.Contains(base, field="title", value="Life")))
jovibon['value'] = 'Jovi, Bon' # fix the typo
cool.save(xmmsc, "SomeCoolCol") # XMMS2 is needed for saving to XMMS2.
This one is based somewhat on alternative 3, with a few mods that I think make it more pythonic, and certainly requires less manual building (more automagic).
from xmmsclient import collections as c
# Get a ref to Collections:Foo
foo = c.Collection('Foo')
# Create a filter that extracts all Bon Jovi 2k6 tracks from the whole medialib.
# Note that this filter filters on several elements, so several match items chained
# one behind the other will be created under the hood.
fil = c.Match(c.Collection(), artist='Bon Jovi', year='2006')
# Intersect the two.
intersect = c.op.And(foo, fil)
# Append another anti-filter on a playlist
intersect.append(c.op.Not(c.Playlist('Bar')))
# All track by Machinae Supremacy.
masu = c.Match(c.Collection()), artist="Machinae Supremacy")
# Combine these two into the final collection
coll = c.op.Or(intersect, masu)
This is supposed to take the good parts of 4 and merge into 3.
from xmmsclient import collections as c
coll = c.And(c.CollectionRef('Foo'),
c.Match(c.Universe(), field='artist', value='Sonic Youth'}),
c.Match(c.Universe(), field='year', value='2006'}))
print coll.operands
# [
,
,
]
del coll.operands[0]
coll.operands.append(c.Reference('Collections:Party music'))
print coll.operands
# [
,
,
]
# make it persistant on server!
xc.coll_save(coll, 'Collections', 'My collection')
m = c.Match(c.Universe(), field='artist', value='Thievery Corporation'})
print m.attributes
# {'field': 'artist', 'value': 'Thievery Corporation'}
print m.operands
# [
]
# get a list of ids matching collection
matchingids = xc.coll_query_id(m)
# I changed my mind..
m.attributes['value'] = 'Air'
songsbyair = xc.coll_query_info(m, ['title', 'duration', 'rating'])
for song in songsbyair:
print "%(album)s - %(title)s (%(duration)s)" % song
This should make clear separation between "operands" and "attributes". Instead of the c[attrib]=aval of alt3 and the c.append(operand) of alt4.
I find the automatic chaining of alt4 scary as it removes the 1:1 mapping to nodes in the dag, and when you later list that collection it will not be the same as you created. It would be better to just make a (trivial) higher level function that does it: (which makes it clear what happens, and doesn't do any magic behind the scenes -- Explicit is better than implicit)
def make_chained_matches(coll, **matches):
for f,v in matches.iteritems:
coll = c.Match(coll, field=f, value=v);
return coll
Also it is important that it is easy to change the attributes. A GUI would probably do something like:
def setup_match_gui(..):
...
self.match_field = SomeInputWidget()
def on_field_change(val):
self.collection.attributes['field'] = val
self.match_field.on_change = on_field_change
self.match_value = SomeInputWidget()
def on_value_change(val):
self.collection.attributes['value'] = val
self.match_field.on_change = on_value_change
this is at least implemented in the git version(works for me)
import xmmsclient
from xmmsclient import collections
import os
import sys
xmms = xmmsclient.XMMS("Sasdlkfjselect")
try:
xmms.connect(os.getenv("XMMS_PATH"))
except IOError, detail:
print "Connection failed:", detail
sys.exit(1)
artist = collections.Match( field="artist", value="Pink" )
album = collections.Has(artist, "album")
title = collections.Match(field="title", value="%pink%")
result = xmms.coll_query_infos( artist, ["artist", "title" ])
result.wait()
print result.value()
print "---"
result = xmms.coll_query_infos( album, ["artist", "title" ])
result.wait()
print result.value()
print "---"
result = xmms.coll_query_infos( title, ["artist", "title" ])
result.wait()
print result.value()
print "---"
result = xmms.coll_query_infos( title | album, ["artist", "title" ])
result.wait()
print result.value()
Other ideas welcome!