Switch to unified view

a/src/mediaserver/cdplugins/uprcl/uprclutils.py b/src/mediaserver/cdplugins/uprcl/uprclutils.py
...
...
14
# You should have received a copy of the GNU General Public License
14
# You should have received a copy of the GNU General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
from __future__ import print_function
16
from __future__ import print_function
17
17
18
import sys
18
import sys
19
import urllib
19
PY3 = sys.version > '3'
20
if PY3:
21
    from urllib.parse import quote as urlquote
22
    import functools
23
else:
24
    from urllib import quote as urlquote
25
    
20
import os
26
import os
21
import glob
27
import glob
22
import subprocess
28
import subprocess
23
import mutagen
29
import mutagen
24
try:
30
import io
25
    from cStringIO import StringIO
26
except ImportError:
27
    from StringIO import StringIO
28
31
29
from upmplgutils import uplog
32
from upmplgutils import uplog
30
33
31
# This must be consistent with what contentdirectory.cxx does
34
# This must be consistent with what contentdirectory.cxx does
32
g_myprefix = '0$uprcl$'
35
g_myprefix = '0$uprcl$'
...
...
102
    else:
105
    else:
103
        li['tp']= 'it'
106
        li['tp']= 'it'
104
        # TBD
107
        # TBD
105
        li['upnp:class'] = 'object.item.audioItem.musicTrack'
108
        li['upnp:class'] = 'object.item.audioItem.musicTrack'
106
109
107
    for oname,dname in upnp2rclfields.iteritems():
110
    for oname,dname in upnp2rclfields.items():
108
        val = getattr(doc, dname)
111
        val = getattr(doc, dname)
109
        if val:
112
        if val:
110
            li[oname] = val
113
            li[oname] = val
111
114
112
    if 'upnp:artist' not in li and doc.albumartist:
115
    if 'upnp:artist' not in li and doc.albumartist:
...
...
133
    # parent process to match urls to plugins)
136
    # parent process to match urls to plugins)
134
    path = doc.getbinurl()
137
    path = doc.getbinurl()
135
    path = path[7:]
138
    path = path[7:]
136
    if 'tt' not in li:
139
    if 'tt' not in li:
137
        li['tt'] = os.path.basename(path.decode('UTF-8', errors = 'replace'))
140
        li['tt'] = os.path.basename(path.decode('UTF-8', errors = 'replace'))
138
    path = os.path.join(pathprefix, path)
141
    path = os.path.join(pathprefix.encode('ascii'), path)
139
    li['uri'] = "http://%s%s" % (httphp, urllib.quote(path))
142
    li['uri'] = "http://%s%s" % (httphp, urlquote(path))
140
    #uplog("rcldoctoentry: uri: %s" % li['uri'])
143
    #uplog("rcldoctoentry: uri: %s" % li['uri'])
141
144
142
    # The album art uri is precooked with httphp and prefix
145
    # The album art uri is precooked with httphp and prefix
143
    if doc.albumarturi:
146
    if doc.albumarturi:
144
        li['upnp:albumArtURI'] = doc.albumarturi
147
        li['upnp:albumArtURI'] = doc.albumarturi
...
...
170
    else:
173
    else:
171
        return os.path.dirname(path)
174
        return os.path.dirname(path)
172
175
173
def embdimgurl(doc, httphp, pathprefix):
176
def embdimgurl(doc, httphp, pathprefix):
174
    if doc.embdimg == 'jpg':
177
    if doc.embdimg == 'jpg':
175
        ext = '.jpg'
178
        ext = b'.jpg'
176
    elif doc.embdimg == '.png':
179
    elif doc.embdimg == '.png':
177
        ext = 'png'
180
        ext = b'png'
178
    else:
181
    else:
179
        return None
182
        return None
180
    path = doc.getbinurl()
183
    path = doc.getbinurl()
181
    path = path[7:]
184
    path = path[7:]
182
    path = urllib.quote(os.path.join(pathprefix, path+ext))
185
    path = urlquote(os.path.join(pathprefix.encode('ascii'), path+ext))
183
    path +=  "?embed=1"
186
    path +=  "?embed=1"
184
    return "http://%s%s" % (httphp, path)
187
    return "http://%s%s" % (httphp, path)
185
188
186
def printable(s):
189
def printable(s):
187
    return s.decode('utf-8', errors='replace') if s else ""
190
    return s.decode('utf-8', errors='replace') if s else ""
188
191
189
def _httpurl(path, httphp, pathprefix):
192
def _httpurl(path, httphp, pathprefix):
190
    return "http://%s%s" % (httphp, urllib.quote(path))
193
    return "http://%s%s" % (httphp, urlquote(path))
191
    
194
    
192
# Find cover art for doc.
195
# Find cover art for doc.
193
#
196
#
194
# We return a special uri if the file has embedded image data, else an
197
# We return a special uri if the file has embedded image data, else an
195
# uri for for the directory cover art (if any).
198
# uri for for the directory cover art (if any).
196
# We are usually called repeatedly for the same directory, so we cache
199
# We are usually called repeatedly for the same directory, so we cache
197
# one result.
200
# one result.
198
_foldercache = {}
201
_foldercache = {}
199
_artexts = ('.jpg', '.png')
202
_artexts = (b'.jpg', b'.png')
200
_artnames = ('folder', 'cover')
203
_artnames = ('folder', 'cover')
201
def docarturi(doc, httphp, pathprefix):
204
def docarturi(doc, httphp, pathprefix):
202
    global _foldercache, _artnames
205
    global _foldercache, _artnames
203
206
204
    if doc.embdimg:
207
    if doc.embdimg:
...
...
209
212
210
    # Check for an image specific to the track file
213
    # Check for an image specific to the track file
211
    path,ext = os.path.splitext(docpath(doc))
214
    path,ext = os.path.splitext(docpath(doc))
212
    for ext in _artexts:
215
    for ext in _artexts:
213
        if os.path.exists(path + ext):
216
        if os.path.exists(path + ext):
214
            return _httpurl(os.path.join(pathprefix, path+ext), httphp,
217
            return _httpurl(os.path.join(pathprefix.encode('ascii'),
215
                           pathprefix)
218
                                         path+ext), httphp, pathprefix)
216
219
217
    # If doc is a directory, this returns itself, else the father dir.
220
    # If doc is a directory, this returns itself, else the father dir.
218
    folder = docfolder(doc)
221
    folder = docfolder(doc)
219
222
220
    if folder not in _foldercache:
223
    if folder not in _foldercache:
...
...
232
                    for ext in _artexts:
235
                    for ext in _artexts:
233
                        if flowersimple == base + ext:
236
                        if flowersimple == base + ext:
234
                            artnm = fsimple
237
                            artnm = fsimple
235
                if artnm:
238
                if artnm:
236
                    _foldercache[folder] = _httpurl(
239
                    _foldercache[folder] = _httpurl(
237
                        urllib.quote(os.path.join(pathprefix, folder, artnm)),
240
                        urlquote(os.path.join(pathprefix, folder, artnm)),
238
                        httphp, pathprefix)
241
                        httphp, pathprefix)
239
                    break
242
                    break
240
        except:
243
        except:
241
            pass
244
            pass
242
245
...
...
255
    al = _keyvalornull(e1, 'upnp:album')
258
    al = _keyvalornull(e1, 'upnp:album')
256
    dr = os.path.dirname(_keyvalornull(e1, 'uri'))
259
    dr = os.path.dirname(_keyvalornull(e1, 'uri'))
257
    tn = _keyvalornull(e1, 'upnp:originalTrackNumber')
260
    tn = _keyvalornull(e1, 'upnp:originalTrackNumber')
258
    uplog("%s tp %s alb %s dir %s tno %s" % (nm, tp,al,dr,tn))
261
    uplog("%s tp %s alb %s dir %s tno %s" % (nm, tp,al,dr,tn))
259
262
260
def cmpentries(e1, e2):
263
def _cmpentries_func(e1, e2):
261
    #uplog("cmpentries");_logentry("e1", e1);_logentry("e2", e2)
264
    #uplog("cmpentries");_logentry("e1", e1);_logentry("e2", e2)
262
    tp1 = e1['tp']
265
    tp1 = e1['tp']
263
    tp2 = e2['tp']
266
    tp2 = e2['tp']
264
    isct1 = tp1 == 'ct'
267
    isct1 = tp1 == 'ct'
265
    isct2 = tp2 == 'ct'
268
    isct2 = tp2 == 'ct'
...
...
296
        return 1
299
        return 1
297
    
300
    
298
    k = 'upnp:originalTrackNumber'
301
    k = 'upnp:originalTrackNumber'
299
    a1 = e1[k] if k in e1 else "0"
302
    a1 = e1[k] if k in e1 else "0"
300
    a2 = e2[k] if k in e2 else "0"
303
    a2 = e2[k] if k in e2 else "0"
304
    try:
301
    return int(a1) - int(a2)
305
        return int(a1) - int(a2)
306
    except:
307
        uplog("upnp:originalTrackNumber %s %s"% (a1, a2))
308
        return 0
302
309
310
if PY3:
311
    cmpentries=functools.cmp_to_key(_cmpentries_func)
312
else:
313
    cmpentries=_cmpentries_func
303
314
304
def rcldirentry(id, pid, title, arturi=None, artist=None, upnpclass=None,
315
def rcldirentry(id, pid, title, arturi=None, artist=None, upnpclass=None,
305
                searchable='1', date=None):
316
                searchable='1', date=None):
306
    """ Create container entry in format expected by parent """
317
    """ Create container entry in format expected by parent """
307
    #uplog("rcldirentry: id %s pid %s tt %s dte %s clss %s artist %s arturi %s" %
318
    #uplog("rcldirentry: id %s pid %s tt %s dte %s clss %s artist %s arturi %s" %
...
...
412
        raise err
423
        raise err
413
        
424
        
414
    f = None
425
    f = None
415
    size = 0
426
    size = 0
416
    if 'audio/mp3' in mutf.mime:
427
    if 'audio/mp3' in mutf.mime:
417
        for tagname in mutf.iterkeys():
428
        for tagname in mutf.keys():
418
            if tagname.startswith('APIC:'):
429
            if tagname.startswith('APIC:'):
419
                #self.em.rclog("mp3 img: %s" % mutf[tagname].mime)
430
                #self.em.rclog("mp3 img: %s" % mutf[tagname].mime)
420
                mtype = mutf[tagname].mime
431
                mtype = mutf[tagname].mime
421
                s = mutf[tagname].data
432
                s = mutf[tagname].data
422
                size = len(s)
433
                size = len(s)
423
                f = StringIO(s)
434
                f = io.BytesIO(s)
424
    elif 'audio/x-flac' in mutf.mime:
435
    elif 'audio/x-flac' in mutf.mime:
425
        if mutf.pictures:
436
        if mutf.pictures:
426
            mtype = mutf.pictures[0].mime
437
            mtype = mutf.pictures[0].mime
427
            size = len(mutf.pictures[0].data)
438
            size = len(mutf.pictures[0].data)
428
            f = StringIO(mutf.pictures[0].data)
439
            f = io.BytesIO(mutf.pictures[0].data)
429
    elif 'audio/mp4' in mutf.mime:
440
    elif 'audio/mp4' in mutf.mime:
430
        if 'covr' in mutf.iterkeys():
441
        if 'covr' in mutf.keys():
431
            format = mutf['covr'][0].imageformat 
442
            format = mutf['covr'][0].imageformat 
432
            if format == mutagen.mp4.AtomDataType.JPEG:
443
            if format == mutagen.mp4.AtomDataType.JPEG:
433
                mtype = 'image/jpeg'
444
                mtype = 'image/jpeg'
434
            else:
445
            else:
435
                mtype = 'image/png'
446
                mtype = 'image/png'
436
            size = len(mutf['covr'][0])
447
            size = len(mutf['covr'][0])
437
            f = StringIO(mutf['covr'][0])
448
            f = io.BytesIO(mutf['covr'][0])
438
449
439
    if f is None:
450
    if f is None:
440
        raise Exception("can't open embedded image")
451
        raise Exception("can't open embedded image")
441
    else:
452
    else:
442
        return mtype, size, f
453
        return mtype, size, f