Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Jean-Francois Dockes
upmpdcli
Commits
af36ad88
Commit
af36ad88
authored
Jan 22, 2017
by
Jean-Francois Dockes
Browse files
none
parent
ce30a15b
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/mediaserver/cdplugins/uprcl/folders.py
View file @
af36ad88
from
__future__
import
print_function
import
os
import
shlex
import
urllib
import
sys
from
uprclutils
import
*
from
recoll
import
recoll
from
recoll
import
rclconfig
...
...
@@ -21,8 +22,8 @@ topdirs = [os.path.expanduser(d) for d in
# The dirvec vector has one entry for each directory. Each entry is a
# dictionary, mapping the names inside the directory to a pair (i,j),
# where:
# - i is an index into dirvec if the name is a directory, else
0
# - j is the index of the doc inside the doc array
# - i is an index into dirvec if the name is a directory, else
-1
# - j is the index of the doc inside the doc array
(or -1 if there is no doc)
#
# Entry 0 in dirvec is special: it holds the 'topdirs' from the recoll
# configuration. The entries are paths instead of simple names, and
...
...
@@ -36,9 +37,12 @@ def rcl2folders(docs):
dirvec
.
append
({})
for
d
in
topdirs
:
topidx
+=
1
dirvec
[
0
][
d
]
=
(
topidx
,
0
)
dirvec
[
0
][
d
]
=
(
topidx
,
-
1
)
dirvec
.
append
({})
# Walk the doc list and update the directory tree according to the
# url (create intermediary directories if needed, create leaf
# entry
for
docidx
in
range
(
len
(
docs
)):
doc
=
docs
[
docidx
]
url
=
doc
.
getbinurl
()
...
...
@@ -48,48 +52,74 @@ def rcl2folders(docs):
except
:
decoded
=
urllib
.
quote
(
url
).
decode
(
'utf-8'
)
# Determine the root entry (topdirs element). Special because
# path not simple name
fathidx
=
-
1
for
rtpath
,
idx
in
dirvec
[
0
].
iteritems
():
if
url
.
startswith
(
rtpath
):
fathidx
=
idx
[
0
]
break
if
fathidx
==
-
1
:
print
(
"No parent in topdirs: %s"
%
decoded
)
uplog
(
"No parent in topdirs: %s"
%
decoded
)
continue
# Compute rest of path
url1
=
url
[
len
(
rtpath
):]
if
len
(
url1
)
==
0
:
continue
# Split path, then walk the vector, possibly creating
# directory entries as needed
path
=
url1
.
split
(
'/'
)[
1
:]
#
print
("%s"%path, file=sys.stderr)
#
uplog
("%s"%path, file=sys.stderr)
for
idx
in
range
(
len
(
path
)):
elt
=
path
[
idx
]
if
elt
in
dirvec
[
fathidx
]:
# This path element was already seen
# If this is the last entry in the path, maybe update
# the doc idx (previous entries were created for
# intermediate elements without a Doc).
#uplog("NEED TO UPDATE DOC")
dirvec
[
fathidx
][
elt
]
=
(
dirvec
[
fathidx
][
elt
][
0
],
docidx
)
# Update fathidx for next iteration
fathidx
=
dirvec
[
fathidx
][
elt
][
0
]
else
:
if
idx
!=
len
(
path
)
-
1
or
doc
.
mtype
==
'inode/directory'
:
# Element has no entry in father directory (hence no
# dirvec entry either).
if
idx
!=
len
(
path
)
-
1
:
# This is an intermediate element. Create a
# Doc-less directory
topidx
+=
1
dirvec
.
append
({})
dirvec
[
fathidx
][
elt
]
=
(
topidx
,
docidx
)
dirvec
[
fathidx
][
elt
]
=
(
topidx
,
-
1
)
fathidx
=
topidx
else
:
dirvec
[
fathidx
][
elt
]
=
(
topidx
,
docidx
)
# Last element. If directory, needs a dirvec entry
if
doc
.
mtype
==
'inode/directory'
:
topidx
+=
1
dirvec
.
append
({})
dirvec
[
fathidx
][
elt
]
=
(
topidx
,
docidx
)
fathidx
=
topidx
else
:
dirvec
[
fathidx
][
elt
]
=
(
-
1
,
docidx
)
if
False
:
for
ent
in
dirvec
:
print
(
"%s"
%
ent
)
uplog
(
"%s"
%
ent
)
return
dirvec
# Fetch all the docs by querying Recoll with [mime:*], 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
):
global
allthedocs
allthedocs
=
[]
rcldb
=
recoll
.
connect
(
confdir
=
confdir
)
rclq
=
rcldb
.
query
()
rclq
.
execute
(
"mime:*"
,
stemming
=
0
)
print
(
"Estimated query results: %d"
%
(
rclq
.
rowcount
))
uplog
(
"Estimated
alldocs
query results: %d"
%
(
rclq
.
rowcount
))
maxcnt
=
0
totcnt
=
0
...
...
@@ -100,12 +130,50 @@ def fetchalldocs(confdir):
totcnt
+=
1
if
(
maxcnt
>
0
and
totcnt
>=
maxcnt
)
or
len
(
docs
)
!=
rclq
.
arraysize
:
break
print
(
"Retrieved %d docs"
%
(
totcnt
,))
fetchalldocs
(
confdir
)
rcl2folders
(
allthedocs
)
print
(
"%s"
%
dirvec
[
0
])
print
(
"%s"
%
dirvec
[
1
])
print
(
"%s"
%
dirvec
[
2
])
print
(
"%s"
%
dirvec
[
3
])
uplog
(
"Retrieved %d docs"
%
(
totcnt
,))
return
allthedocs
def
inittree
(
confdir
):
global
g_alldocs
,
g_dirvec
g_alldocs
=
fetchalldocs
(
confdir
)
g_dirvec
=
rcl2folders
(
g_alldocs
)
g_myprefix
=
'0$uprcl$folders'
# objid is like folders$index
# flag is meta or children.
def
browse
(
pid
,
flag
):
global
g_alldocs
,
g_dirvec
if
not
pid
.
startswith
(
g_myprefix
):
uplog
(
"folders.browse: bad pid %s"
%
pid
)
return
[]
try
:
len
(
g_alldocs
)
except
:
inittree
(
confdir
)
if
len
(
g_alldocs
)
==
0
:
uplog
(
"folders:browse: no docs"
)
return
[]
diridx
=
pid
[
len
(
g_myprefix
):]
if
not
diridx
:
diridx
=
0
else
:
diridx
=
int
(
diridx
[
1
:])
if
diridx
>=
len
(
g_dirvec
):
uplog
(
"folders:browse: bad pid %s"
%
pid
)
return
[]
entries
=
[]
Need
to
treat
diridx
0
special
(
take
simple
paths
)
for
nm
,
ids
in
g_dirvec
[
diridx
].
iteritems
():
id
=
g_myprefix
+
'$'
+
str
(
ids
[
0
])
entries
.
append
(
rcldirentry
(
id
,
pid
,
nm
))
return
entries
src/mediaserver/cdplugins/uprcl/uprcl-app.py
0 → 100755
View file @
af36ad88
#!/usr/bin/env python
#
# Copyright (C) 2016 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from
__future__
import
print_function
import
sys
import
os
import
json
import
posixpath
import
re
import
conftree
import
cmdtalkplugin
import
folders
from
uprclutils
import
*
# Func name to method mapper
dispatcher
=
cmdtalkplugin
.
Dispatch
()
# Pipe message handler
msgproc
=
cmdtalkplugin
.
Processor
(
dispatcher
)
is_logged_in
=
False
def
maybelogin
():
global
httphp
global
pathprefix
global
is_logged_in
if
is_logged_in
:
return
True
if
"UPMPD_HTTPHOSTPORT"
not
in
os
.
environ
:
raise
Exception
(
"No UPMPD_HTTPHOSTPORT in environment"
)
httphp
=
os
.
environ
[
"UPMPD_HTTPHOSTPORT"
]
if
"UPMPD_PATHPREFIX"
not
in
os
.
environ
:
raise
Exception
(
"No UPMPD_PATHPREFIX in environment"
)
pathprefix
=
os
.
environ
[
"UPMPD_PATHPREFIX"
]
if
"UPMPD_CONFIG"
not
in
os
.
environ
:
raise
Exception
(
"No UPMPD_CONFIG in environment"
)
upconfig
=
conftree
.
ConfSimple
(
os
.
environ
[
"UPMPD_CONFIG"
])
@
dispatcher
.
record
(
'trackuri'
)
def
trackuri
(
a
):
msgproc
.
log
(
"trackuri: [%s]"
%
a
)
trackid
=
trackid_from_urlpath
(
pathprefix
,
a
)
maybelogin
()
mime
,
kbs
=
get_mimeandkbs
()
return
{
'media_url'
:
media_url
,
'mimetype'
:
mime
,
'kbs'
:
kbs
}
@
dispatcher
.
record
(
'browse'
)
def
browse
(
a
):
msgproc
.
log
(
"browse: [%s]"
%
a
)
if
'objid'
not
in
a
:
raise
Exception
(
"No objid in args"
)
objid
=
a
[
'objid'
]
bflg
=
a
[
'flag'
]
if
'flag'
in
a
else
'children'
if
re
.
match
(
'0\$uprcl\$'
,
objid
)
is
None
:
raise
Exception
(
"bad objid [%s]"
%
objid
)
maybelogin
()
idpath
=
objid
.
replace
(
'0$uprcl$'
,
''
,
1
)
msgproc
.
log
(
"browse: idpath: %s"
%
idpath
)
entries
=
[]
if
bflg
==
'meta'
:
m
=
re
.
match
(
'.*\$(.+)$'
,
idpath
)
if
m
:
trackid
=
m
.
group
(
1
)
# get doc from trackid or whatever
doc
=
{}
entries
+=
trackentries
(
httphp
,
pathprefix
,
objid
,
[])
else
:
if
not
idpath
:
# Root dir
entries
.
append
(
rcldirentry
(
'0$uprcl$'
+
'folders'
,
'0$uprcl$'
,
'[folders]'
))
if
idpath
.
startswith
(
"folders"
):
entries
=
folders
.
browse
(
objid
,
bflg
)
else
:
pass
#msgproc.log("%s" % entries)
encoded
=
json
.
dumps
(
entries
)
return
{
"entries"
:
encoded
}
@
dispatcher
.
record
(
'search'
)
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
)
maybelogin
()
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
)
return
{
"entries"
:
encoded
}
msgproc
.
log
(
"Uprcl running"
)
msgproc
.
mainloop
()
src/mediaserver/cdplugins/uprcl/uprclutils.py
0 → 100644
View file @
af36ad88
from
__future__
import
print_function
import
sys
def
rcldocs2entries
(
httphp
,
pathprefix
,
objid
,
docs
):
"""
Transform a list of Doc objects into the format expected by the parent
Args:
httphp: the hostport part of the generated track urls
pathprefix: is provided by our parent process (it's used to
what plugin an url belongs too when needed for
translating the internal into the real url (for plugins
based on external-services)
objid (str): objid for the browsed object (the parent container)
docs is the array of Doc objects to be translated
Returns:
A list of dicts, each representing an UPnP item, with the
keys as expected in the plgwithslave.cxx resultToEntries() function.
The permanent URIs, are of the following form, based on the
configured host:port and pathprefix arguments and track Id:
http://host:port/pathprefix/track?version=1&trackId=<trackid>
"""
global
default_mime
,
default_samplerate
entries
=
[]
for
doc
in
docs
:
li
=
{}
li
[
'pid'
]
=
objid
li
[
'id'
]
=
objid
+
'$'
+
"%s"
%
track
.
id
li
[
'tt'
]
=
doc
.
title
# URL: we need transformation rules from the file:// recoll url to an http
# one appropriate for our media server
li
[
'uri'
]
=
'http://%s'
%
httphp
+
\
posixpath
.
join
(
pathprefix
,
'track?version=1&trackId=%s'
%
track
.
id
)
li
[
'tp'
]
=
'it'
if
doc
.
album
:
li
[
'upnp:album'
]
=
doc
.
album
# !! Albumart will have to come from somewhere else !
### #if doc.albumarturi:
### #li['upnp:albumArtURI'] = track.album.image
# Date format ?
if
doc
.
date
:
li
[
'releasedate'
]
=
doc
.
date
li
[
'upnp:originalTrackNumber'
]
=
str
(
doc
.
tracknumber
)
li
[
'upnp:artist'
]
=
doc
.
artist
li
[
'upnp:genre'
]
=
doc
.
genre
li
[
'dc:title'
]
=
doc
.
title
li
[
'upnp:class'
]
=
track
.
upnpclass
li
[
'res:mime'
]
=
doc
.
mtype
### li['discnumber'] = str(track.disc_num)
### Need to extract the audio params from mutagen output !
#li['duration'] = track.duration
#li['res:samplefreq'] = default_samplerate
#albumartist=
#comment=
#composer=
#conductor=
#discnumber=
#genre=
#lyricist=
#lyrics=
entries
.
append
(
li
)
return
entries
def
rcldirentry
(
id
,
pid
,
title
,
arturi
=
None
,
artist
=
None
,
upnpclass
=
None
):
""" Create container entry in format expected by parent """
ret
=
{
'id'
:
id
,
'pid'
:
pid
,
'tt'
:
title
,
'tp'
:
'ct'
,
'searchable'
:
'1'
}
if
arturi
:
ret
[
'upnp:albumArtURI'
]
=
arturi
if
artist
:
ret
[
'upnp:artist'
]
=
artist
if
upnpclass
:
ret
[
'upnp:class'
]
=
upnpclass
else
:
ret
[
'upnp:class'
]
=
'object.container'
return
ret
def
uplog
(
s
):
print
((
"%s: %s"
%
(
'uprcl'
,
s
)).
encode
(
'utf-8'
),
file
=
sys
.
stderr
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment