|
a |
|
b/src/mediaserver/cdplugins/uprcl/uprclsearch.py |
|
|
1 |
#!/usr/bin/env python
|
|
|
2 |
from __future__ import print_function
|
|
|
3 |
|
|
|
4 |
def _getchar(s, i):
|
|
|
5 |
if i < len(s):
|
|
|
6 |
return i+1,s[i]
|
|
|
7 |
else:
|
|
|
8 |
return i,None
|
|
|
9 |
|
|
|
10 |
def _readword(s, i):
|
|
|
11 |
w = ''
|
|
|
12 |
for j in range(i, len(s)):
|
|
|
13 |
if s[j].isspace():
|
|
|
14 |
return j,w
|
|
|
15 |
w += s[j]
|
|
|
16 |
return j,w
|
|
|
17 |
|
|
|
18 |
# Called with '"' already read:
|
|
|
19 |
def _readstring(s, i):
|
|
|
20 |
str = '"'
|
|
|
21 |
escape = False
|
|
|
22 |
for j in range(i, len(s)):
|
|
|
23 |
#print("s[j] [%s] out now [%s]" % (s[j],out))
|
|
|
24 |
if s[j] == '\\':
|
|
|
25 |
if not escape:
|
|
|
26 |
escape = True
|
|
|
27 |
str += '\\'
|
|
|
28 |
continue
|
|
|
29 |
|
|
|
30 |
if s[j] == '"':
|
|
|
31 |
str += '"'
|
|
|
32 |
if not escape:
|
|
|
33 |
return j+1, str
|
|
|
34 |
else:
|
|
|
35 |
str += s[j]
|
|
|
36 |
|
|
|
37 |
escape = False
|
|
|
38 |
|
|
|
39 |
return len(s), str
|
|
|
40 |
|
|
|
41 |
def upnpsearchtorecoll(s):
|
|
|
42 |
s = s.replace('\t', ' ')
|
|
|
43 |
s = s.replace('\n', ' ')
|
|
|
44 |
s = s.replace('\r', ' ')
|
|
|
45 |
s = s.replace('\f', ' ')
|
|
|
46 |
|
|
|
47 |
out = []
|
|
|
48 |
hadDerived = False
|
|
|
49 |
i = 0
|
|
|
50 |
while True:
|
|
|
51 |
i,c = _getchar(s, i)
|
|
|
52 |
if not c:
|
|
|
53 |
break
|
|
|
54 |
|
|
|
55 |
if c.isspace():
|
|
|
56 |
continue
|
|
|
57 |
|
|
|
58 |
if c == "*":
|
|
|
59 |
if (len(out) > 1 or (len(out) == 1 and not out[-1].isspace())) or \
|
|
|
60 |
(len(s[i:]) and not s[i:].isspace()):
|
|
|
61 |
raise Exception("If * is used it must be the only input")
|
|
|
62 |
out = ["mime:*"]
|
|
|
63 |
break
|
|
|
64 |
|
|
|
65 |
if c == '(' or c == ')' or c == '>' or c == '<' or c == '=':
|
|
|
66 |
out.append(c)
|
|
|
67 |
else:
|
|
|
68 |
if c == '"':
|
|
|
69 |
i,w = _readstring(s, i)
|
|
|
70 |
if not w.endswith('"'):
|
|
|
71 |
raise Exception("Unterminated string in [%s]" % out)
|
|
|
72 |
else:
|
|
|
73 |
i -= 1
|
|
|
74 |
i,w = _readword(s, i)
|
|
|
75 |
|
|
|
76 |
#print("Got word [%s]" % w)
|
|
|
77 |
if w == 'contains':
|
|
|
78 |
out.append(':')
|
|
|
79 |
elif w == 'doesNotContain':
|
|
|
80 |
if len(out) < 1:
|
|
|
81 |
raise Exception("doesNotContain can't be the first word")
|
|
|
82 |
out.insert(-1, "-")
|
|
|
83 |
out.append(':')
|
|
|
84 |
elif w == 'derivedFrom':
|
|
|
85 |
hadDerived = True
|
|
|
86 |
out.append(':')
|
|
|
87 |
elif w == 'true':
|
|
|
88 |
out.append('*')
|
|
|
89 |
elif w == 'false':
|
|
|
90 |
out.append('xxxjanzocsduochterrrrm')
|
|
|
91 |
elif w == 'exists':
|
|
|
92 |
out.append(':')
|
|
|
93 |
elif w == 'and':
|
|
|
94 |
# Recoll has implied AND, but see next
|
|
|
95 |
pass
|
|
|
96 |
elif w == 'or':
|
|
|
97 |
# Does not work because OR/AND priorities are reversed
|
|
|
98 |
# between recoll and upnp. This would be very
|
|
|
99 |
# difficult to correct, let's hope that the callers
|
|
|
100 |
# use parenthesese
|
|
|
101 |
out.append('OR')
|
|
|
102 |
else:
|
|
|
103 |
if hadDerived:
|
|
|
104 |
hadDerived = False
|
|
|
105 |
if len(w) >= 1 and w[-1] == '"':
|
|
|
106 |
w = w[:-1] + '*' + '"'
|
|
|
107 |
else:
|
|
|
108 |
w += '*'
|
|
|
109 |
out.append(w)
|
|
|
110 |
|
|
|
111 |
ostr = ""
|
|
|
112 |
for tok in out:
|
|
|
113 |
ostr += tok + " "
|
|
|
114 |
return ostr
|
|
|
115 |
|
|
|
116 |
|
|
|
117 |
if __name__ == '__main__':
|
|
|
118 |
s = '(upnp:artist derivedFrom "abc\\"def\\g") or (dc:title:xxx) '
|
|
|
119 |
print("INPUT: %s" % s)
|
|
|
120 |
o = upnpsearchtorecoll(s)
|
|
|
121 |
print("OUTPUT: %s" % o)
|