--- a/src/mediaserver/cdplugins/uprcl/uprclutils.py
+++ b/src/mediaserver/cdplugins/uprcl/uprclutils.py
@@ -3,6 +3,7 @@
import sys
import posixpath
import urllib
+import os
audiomtypes = frozenset([
'audio/mpeg',
@@ -11,9 +12,20 @@
'audio/aac',
'audio/mp4',
'audio/x-aiff',
- 'audio/x-wav'
+ 'audio/x-wav',
+ 'inode/directory'
])
+upnp2rclfields = {'upnp:album': 'album',
+ 'releasedate' : 'date',
+ 'upnp:originalTrackNumber' : 'tracknumber',
+ 'upnp:artist' : 'artist',
+ 'upnp:genre' : 'genre',
+ 'res:mime' : 'mtype',
+ 'duration' : 'duration',
+ 'res:samplefreq' : 'sample_rate'
+ }
+
def rcldoctoentry(id, pid, httphp, pathprefix, doc):
"""
Transform a Doc objects into the format expected by the parent
@@ -38,8 +50,8 @@
http://host:port/pathprefix/track?version=1&trackId=<trackid>
"""
- uplog("rcldoctoentry: pid %s id %s httphp %s pathprefix %s" %
- (pid, id, httphp, pathprefix))
+ uplog("rcldoctoentry: pid %s id %s mtype %s" %
+ (pid, id, doc.mtype))
li = {}
if doc.mtype not in audiomtypes:
@@ -47,7 +59,7 @@
li['pid'] = pid
li['id'] = id
- li['tp'] = 'it'
+ li['tp'] = 'ct' if doc.mtype == 'inode/directory' else 'it'
# Why no dc.title??
li['tt'] = doc.title
@@ -72,11 +84,7 @@
#lyricist=
#lyrics=
- for oname,dname in [('upnp:album', 'album'), ('releasedate','date'),
- ('upnp:originalTrackNumber', 'tracknumber'),
- ('upnp:artist', 'artist'), ('upnp:genre', 'genre'),
- ('res:mime', 'mtype'), ('duration', 'duration'),
- ('res:samplefreq', 'sample_rate')]:
+ for oname,dname in upnp2rclfields.iteritems():
val = getattr(doc, dname)
if val:
li[oname] = val
@@ -98,6 +106,49 @@
uplog("rcldoctoentry: uri: %s" % li['uri'])
return li
+def cmpentries(e1, e2):
+ tp1 = e1['tp']
+ tp2 = e2['tp']
+ isct1 = tp1 == 'ct'
+ isct2 = tp2 == 'ct'
+
+ # Containers come before items, and are sorted in alphabetic order
+ if isct1 and not isct2:
+ return 1
+ elif not isct1 and isct2:
+ return -1
+ elif isct1 and isct2:
+ tt1 = e1['tt']
+ tt2 = e2['tt']
+ if tt1 < tt2:
+ return -1
+ elif tt1 > tt2:
+ return 1
+ else:
+ return 0
+
+ # Tracks. Sort by album then directory then track number
+ k = 'upnp:album'
+ a1 = e1[k] if k in e1 else ""
+ a2 = e2[k] if k in e2 else ""
+ if a1 < a2:
+ return -1
+ elif a1 > a2:
+ return 1
+
+ d1 = os.path.dirname(e1['uri'])
+ d2 = os.path.dirname(e2['uri'])
+ if d1 < d2:
+ return -1
+ elif d1 > d2:
+ return 1
+
+ k = 'upnp:originalTrackNumber'
+ a1 = e1[k] if k in e1 else "0"
+ a2 = e2[k] if k in e2 else "0"
+ return int(a1) - int(a2)
+
+
def rclpathtoreal(path, pathprefix, httphp, pathmap):
path = path.replace(pathprefix, '', 1)
found = False
@@ -109,9 +160,10 @@
return None
return "http://" + httphp + path
-def rcldirentry(id, pid, title, arturi=None, artist=None, upnpclass=None):
+def rcldirentry(id, pid, title, arturi=None, artist=None, upnpclass=None,
+ searchable='1'):
""" Create container entry in format expected by parent """
- ret = {'id':id, 'pid':pid, 'tt':title, 'tp':'ct', 'searchable':'1'}
+ ret = {'id':id, 'pid':pid, 'tt':title, 'tp':'ct', 'searchable':searchable}
if arturi:
ret['upnp:albumArtURI'] = arturi
if artist:
@@ -124,3 +176,70 @@
def uplog(s):
print(("%s: %s" % ('uprcl', s)).encode('utf-8'), file=sys.stderr)
+
+
+# Parse string into (possibly multiword) tokens
+# 'a b "one phrase" c' -> [a, b, 'one phrase', c]
+def stringToStrings(str):
+ # States. Note that ESCAPE can only occur inside INQUOTE
+ SPACE, TOKEN, INQUOTE, ESCAPE = range(4)
+
+ tokens = []
+ curtok = ""
+ state = SPACE;
+
+ for c in str:
+ if c == '"':
+ if state == SPACE:
+ state = INQUOTE
+ elif state == TOKEN:
+ curtok += '"'
+ elif state == INQUOTE:
+ if curtok:
+ tokens.append(curtok);
+ curtok = ""
+ state = SPACE
+ elif state == ESCAPE:
+ curtok += '"'
+ state = INQUOTE
+ continue;
+
+ elif c == '\\':
+ if state == SPACE or state == TOKEN:
+ curtok += '\\'
+ state = TOKEN
+ elif state == INQUOTE:
+ state = ESCAPE
+ elif state == ESCAPE:
+ curtok += '\\'
+ state = INQUOTE
+ continue
+
+ elif c == ' ' or c == '\t' or c == '\n' or c == '\r':
+ if state == SPACE or state == TOKEN:
+ if curtok:
+ tokens.append(curtok)
+ curtok = ""
+ state = SPACE
+ elif state == INQUOTE or state == ESCAPE:
+ curtok += c
+ continue;
+
+ else:
+ if state == ESCAPE:
+ state = INQUOTE
+ elif state == SPACE:
+ state = TOKEN
+ elif state == TOKEN or state == INQUOTE:
+ pass
+ curtok += c
+
+ if state == SPACE:
+ pass
+ elif state == TOKEN:
+ if curtok:
+ tokens.append(curtok)
+ elif state == INQUOTE or state == ESCAPE:
+ raise Exception("Bad string: <" + str + ">")
+
+ return tokens