Commit 7ebbdb17 authored by Jean-Francois Dockes's avatar Jean-Francois Dockes
Browse files

none

parent e7698b09
......@@ -23,17 +23,22 @@ import posixpath
import re
import conftree
import cmdtalkplugin
import folders
import uprclfolders
import uprclsearch
from uprclutils import *
from recoll import recoll
from recoll import rclconfig
g_myprefix = '0$uprcl$folders'
# Func name to method mapper
dispatcher = cmdtalkplugin.Dispatch()
# Pipe message handler
msgproc = cmdtalkplugin.Processor(dispatcher)
def module_init():
global httphp
global pathprefix
def uprcl_init():
global httphp, pathprefix, uprclhost, pathmap
if "UPMPD_HTTPHOSTPORT" not in os.environ:
raise Exception("No UPMPD_HTTPHOSTPORT in environment")
......@@ -45,24 +50,26 @@ def module_init():
raise Exception("No UPMPD_CONFIG in environment")
upconfig = conftree.ConfSimple(os.environ["UPMPD_CONFIG"])
global uprclhost, pathmap
uprclhost = upconfig.get("uprclhost")
if uprclhost is None:
msgproc.log("uprcl init: no uprclhost in config file")
return False
raise Exception("uprclhost not in config")
pthstr = upconfig.get("uprclpaths")
if pthstr is None:
msgproc.log("uprcl init: no uprclpaths in config file")
return False
raise Exception("uprclpaths not in config")
lpth = pthstr.split(',')
pathmap = {}
for ptt in lpth:
l = ptt.split(':')
pathmap[l[0]] = l[1]
return True
global rclconfdir
rclconfdir = upconfig.get("uprclconfdir")
if rclconfdir is None:
raise Exception("uprclconfdir not in config")
uprclfolders.inittree(rclconfdir)
@dispatcher.record('trackuri')
def trackuri(a):
......@@ -105,7 +112,7 @@ def browse(a):
entries.append(rcldirentry('0$uprcl$' + 'folders', '0$uprcl$',
'[folders]'))
elif idpath.startswith("folders"):
entries = folders.browse(objid, bflg, httphp, pathprefix)
entries = uprclfolders.browse(objid, bflg, httphp, pathprefix)
else:
pass
......@@ -119,37 +126,36 @@ def browse(a):
def search(a):
msgproc.log("search: [%s]" % a)
objid = a['objid']
field = a['field'] if 'field' in a else None
value = a['value']
objkind = a['objkind'] if 'objkind' in a else None
if re.match('0\$uprcl\$', objid) is None:
raise Exception("bad objid [%s]" % objid)
upnps = a['origsearch']
rcls = uprclsearch.upnpsearchtorecoll(upnps)
uplog("Search: recoll search: %s" % rcls)
searchresults = session.search(value)
if objkind and objkind not in ['artist', 'album', 'playlist', 'track']:
msgproc.log('Unknown objkind \'%s\'' % objkind)
objkind = None
if objkind is None or objkind == 'artist':
view(searchresults.artists,
urls_from_id(artist_view, searchresults.artists), end=False)
if objkind is None or objkind == 'album':
view(searchresults.albums,
urls_from_id(album_view, searchresults.albums), end=False)
if objkind is None or objkind == 'playlist':
view(searchresults.playlists,
urls_from_id(playlist_view, searchresults.playlists), end=False)
if objkind is None or objkind == 'track':
track_list(searchresults.tracks)
#msgproc.log("%s" % xbmcplugin.entries)
encoded = json.dumps(xbmcplugin.entries)
rcldb = recoll.connect(confdir=rclconfdir)
rclq = rcldb.query()
rclq.execute(rcls)
uplog("Estimated query results: %d" % (rclq.rowcount))
entries = []
maxcnt = 0
totcnt = 0
while True:
docs = rclq.fetchmany()
for doc in docs:
id = g_myprefix + '$' + 'seeyoulater'
e = rcldoctoentry(id, objid, httphp, pathprefix, doc)
entries.append(e)
totcnt += 1
if (maxcnt > 0 and totcnt >= maxcnt) or len(docs) != rclq.arraysize:
break
uplog("Search retrieved %d docs" % (totcnt,))
encoded = json.dumps(entries)
return {"entries" : encoded}
if not module_init():
msgproc.log("Uprcl init failed")
sys.exit(1)
uprcl_init()
msgproc.log("Uprcl running")
msgproc.mainloop()
......@@ -25,7 +25,7 @@ g_myprefix = '0$uprcl$folders'
# configuration. The entries are paths instead of simple names, and
# the doc index (j) is 0. The dir index points normally to a dirvec
# entry.
def rcl2folders(docs, confdir):
def _rcl2folders(docs, confdir):
global dirvec
dirvec = []
......@@ -113,7 +113,7 @@ def rcl2folders(docs, confdir):
# which is guaranteed to match every doc without overflowing the query
# size (because the number of mime types is limited). Something like
# title:* would overflow.
def fetchalldocs(confdir):
def _fetchalldocs(confdir):
allthedocs = []
rcldb = recoll.connect(confdir=confdir)
......@@ -134,37 +134,33 @@ def fetchalldocs(confdir):
return allthedocs
# Internal init
# Initialize (read recoll data and build tree)
def inittree(confdir):
global g_alldocs, g_dirvec
g_alldocs = fetchalldocs(confdir)
g_dirvec = rcl2folders(g_alldocs, confdir)
g_alldocs = _fetchalldocs(confdir)
g_dirvec = _rcl2folders(g_alldocs, confdir)
## This needs to come from upmpdcli.conf
confdir = "/home/dockes/.recoll-mp3"
inittree(confdir)
def cmpentries(e1, e2):
#uplog("cmpentries: %s %s" % (e1['tt'], e2['tt']))
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 tp1 == 'ct' and tp2 != 'ct':
if isct1 and not isct2:
return 1
elif tp1 != 'ct' and tp2 == 'ct':
elif not isct1 and isct2:
return -1
elif tp1 == 'ct' and tp2 == 'ct':
if tp1 < tp2:
elif isct1 and isct2:
tt1 = e1['tt']
tt2 = e2['tt']
if tt1 < tt2:
return -1
elif tp1 > tp2:
elif tt1 > tt2:
return 1
else:
return 0
# 2 tracks. Sort by album then track number
k = 'upnp:album'
a1 = e1[k] if k in e1 else ""
......@@ -179,6 +175,8 @@ def cmpentries(e1, e2):
a2 = e2[k] if k in e2 else "0"
return int(a1) - int(a2)
# Browse method
# objid is like folders$index
# flag is meta or children.
def browse(pid, flag, httphp, pathprefix):
......@@ -224,4 +222,4 @@ def browse(pid, flag, httphp, pathprefix):
entries.append(e)
#return entries
return sorted(entries, cmp=cmpentries)
return sorted(entries, cmp=_cmpentries)
#!/usr/bin/env python
from __future__ import print_function
def _getchar(s, i):
if i < len(s):
return i+1,s[i]
else:
return i,None
def _readword(s, i):
w = ''
for j in range(i, len(s)):
if s[j].isspace():
return j,w
w += s[j]
return j,w
# Called with '"' already read:
def _readstring(s, i):
str = '"'
escape = False
for j in range(i, len(s)):
#print("s[j] [%s] out now [%s]" % (s[j],out))
if s[j] == '\\':
if not escape:
escape = True
str += '\\'
continue
if s[j] == '"':
str += '"'
if not escape:
return j+1, str
else:
str += s[j]
escape = False
return len(s), str
def upnpsearchtorecoll(s):
s = s.replace('\t', ' ')
s = s.replace('\n', ' ')
s = s.replace('\r', ' ')
s = s.replace('\f', ' ')
out = []
hadDerived = False
i = 0
while True:
i,c = _getchar(s, i)
if not c:
break
if c.isspace():
continue
if c == "*":
if (len(out) > 1 or (len(out) == 1 and not out[-1].isspace())) or \
(len(s[i:]) and not s[i:].isspace()):
raise Exception("If * is used it must be the only input")
out = ["mime:*"]
break
if c == '(' or c == ')' or c == '>' or c == '<' or c == '=':
out.append(c)
else:
if c == '"':
i,w = _readstring(s, i)
if not w.endswith('"'):
raise Exception("Unterminated string in [%s]" % out)
else:
i -= 1
i,w = _readword(s, i)
#print("Got word [%s]" % w)
if w == 'contains':
out.append(':')
elif w == 'doesNotContain':
if len(out) < 1:
raise Exception("doesNotContain can't be the first word")
out.insert(-1, "-")
out.append(':')
elif w == 'derivedFrom':
hadDerived = True
out.append(':')
elif w == 'true':
out.append('*')
elif w == 'false':
out.append('xxxjanzocsduochterrrrm')
elif w == 'exists':
out.append(':')
elif w == 'and':
# Recoll has implied AND, but see next
pass
elif w == 'or':
# Does not work because OR/AND priorities are reversed
# between recoll and upnp. This would be very
# difficult to correct, let's hope that the callers
# use parenthesese
out.append('OR')
else:
if hadDerived:
hadDerived = False
if len(w) >= 1 and w[-1] == '"':
w = w[:-1] + '*' + '"'
else:
w += '*'
out.append(w)
ostr = ""
for tok in out:
ostr += tok + " "
return ostr
if __name__ == '__main__':
s = '(upnp:artist derivedFrom "abc\\"def\\g") or (dc:title:xxx) '
print("INPUT: %s" % s)
o = upnpsearchtorecoll(s)
print("OUTPUT: %s" % o)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment