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 not objid.startswith(g_myprefix): raise Exception("bad objid <%s>" % objid) idpath = objid.replace(g_myprefix, '', 1) msgproc.log("browse: idpath: <%s>" % idpath) entries = [] nocache = "0" if bflg == 'meta': raise Exception("uprcl-app: browse: can't browse meta for now") else: if not _ready(): entries = [ rcldirentry(objid + 'notready', objid, 'Initializing...'), ] nocache = "1" elif not idpath: entries = _rootentries() else: entries = _browsedispatch(objid, bflg, httphp, pathprefix) #msgproc.log("%s" % entries) encoded = json.dumps(entries) return {"entries": encoded, "nocache": nocache}
def _tagsbrowseitems(self, pid, qpath, i, selwhere, values): stmt = 'SELECT docidx FROM tracks ' + selwhere c = self._conn.cursor() rows = c.execute(stmt, values) docids = [r[0] for r in rows] albids = self._subtreealbums(selwhere, values) entries = [] displaytracks = True if len(albids) == 1: # Only display '>> Complete album' if not all tracks # already there. If all tracks are there, we display # the album entry (with the same id value: show album) albid = albids[0] tlist = self._trackentriesforalbum(albid, pid) # Replace $items with $albums for the album entry id = pid.replace('$items', '$albums') + '$' + str(albid) + '$showca' if len(tlist) != len(docids): entries.append(rcldirentry(id, pid, '>> Complete Album')) else: displaytracks = False el = self._direntriesforalbums(pid, "WHERE album_id = %s" % albid) el[0]['id'] = id entries.append(el[0]) if displaytracks: rcldocs = uprclinit.g_trees['folders'].rcldocs() entries += [ rcldoctoentry(pid + '$i' + str(docid), pid, self._httphp, self._pprefix, rcldocs[docid]) for docid in docids ] return sorted(entries, key=cmpentries)
def _direntriesforalbums(self, pid, where, path=''): uplog("_direntriesforalbums. where: %s" % where) c = self._conn.cursor() args = (path + '%', ) if path else () if path: if not where: where = '''WHERE albfolder LIKE ?''' else: where += ''' AND albfolder LIKE ?''' substmt = '''SELECT DISTINCT albalb FROM ALBUMS %s''' % where where = '''WHERE album_id IN (%s)''' % substmt else: if not where: where = '''WHERE albtdisc IS NULL''' else: where += ''' AND albtdisc IS NULL''' stmt = '''SELECT album_id, albtitle, albarturi, albdate, artist.value FROM albums LEFT JOIN artist ON artist.artist_id = albums.artist_id %s ORDER BY albtitle''' % where uplog('direntriesforalbums: %s' % stmt) c.execute(stmt, args) entries = [] for r in c: id = pid + '$' + str(r[0]) entries.append( rcldirentry(id, pid, r[1], arturi=r[2], date=r[3], artist=r[4], upnpclass='object.container.album.musicAlbum')) return entries
def rootentries(self, pid, path=''): uplog("rootentries: pid %s path %s" % (pid, path)) entries = [] nalbs = self._albcntforfolder(path) entries.append(rcldirentry(pid + 'albums', pid, nalbs + ' albums')) if path: where = ' WHERE tracks.path LIKE ? ' args = (path + '%', ) else: where = ' ' args = () c = self._conn.cursor() stmt = "SELECT COUNT(*) from tracks" c.execute(stmt + where, args) nitems = str(c.fetchone()[0]) entries.append(rcldirentry(pid + 'items', pid, nitems + ' items')) subqs = self._subtreetags(where, args) for tt in subqs: entries.append( rcldirentry(pid + '=' + tt, pid, g_tagdisplaytag[tt])) return entries
def browse(self, pid, flag): idx = self._objidtoidx(pid) folders = uprclinit.g_trees['folders'] rcldocs = folders.rcldocs() entries = [] if idx == 0: # Browsing root for i in range(len(self.utidx))[1:]: doc = rcldocs[self.utidx[i]] id = self._idprefix + '$p' + str(i) title = doc.title if doc.title else doc.filename e = rcldirentry(id, pid, title, upnpclass='object.container.playlistContainer') if e: entries.append(e) else: pldoc = rcldocs[self.utidx[idx]] plpath = uprclutils.docpath(pldoc) #uplog("playlists: plpath %s" % plpath) try: m3u = uprclutils.M3u(plpath) except Exception as ex: uplog("M3u open failed: %s %s" % (plpath, ex)) return entries cnt = 1 for url in m3u: doc = recoll.Doc() if m3u.urlRE.match(url): # Actual URL (usually http). Create bogus doc doc.setbinurl(bytearray(url)) elt = os.path.split(url)[1] doc.title = elt.decode('utf-8', errors='ignore') doc.mtype = "audio/mpeg" else: doc.setbinurl(bytearray(b'file://' + url)) fathidx, docidx = folders._stat(doc) if docidx < 0: uplog("playlists: can't stat %s" % doc.getbinurl()) continue doc = rcldocs[docidx] id = pid + '$e' + str(len(entries)) e = rcldoctoentry(id, pid, self._httphp, self._pprefix, doc) if e: entries.append(e) return sorted(entries, key=cmpentries)
def browse(pid, flag, httphp, pathprefix): diridx = _objidtodiridx(pid) # If there is only one entry in root, skip it. This means that 0 # and 1 point to the same dir, but this does not seem to be an # issue if diridx == 0 and len(dirvec[0]) == 2: diridx = 1 entries = [] # The basename call is just for diridx==0 (topdirs). Remove it if # this proves a performance issue for nm, ids in _dirvec[diridx].iteritems(): if nm == "..": continue thisdiridx = ids[0] thisdocidx = ids[1] if thisdocidx >= 0: doc = g_alldocs[thisdocidx] else: uplog("No doc for %s" % pid) doc = None if thisdiridx >= 0: # Skip empty directories if len(dirvec[thisdiridx]) == 1: continue id = _foldersIdPfx + '$' + 'd' + str(thisdiridx) if doc and doc.albumarturi: arturi = doc.albumarturi else: arturi = _arturifordir(thisdiridx) entries.append( rcldirentry(id, pid, os.path.basename(nm), arturi=arturi)) else: # Not a directory. docidx had better been set if thisdocidx == -1: uplog("folders:docidx -1 for non-dir entry %s" % nm) continue doc = g_alldocs[thisdocidx] id = _foldersIdPfx + '$i' + str(thisdocidx) e = rcldoctoentry(id, pid, httphp, pathprefix, doc) if e: entries.append(e) return sorted(entries, cmp=cmpentries)
def _tagsbrowsealbums(self, pid, qpath, i, selwhere, values): uplog("_tagsbrowsealbums: pid %s qpath %s i %s selwhere %s values %s" % (pid, qpath, i, selwhere, values)) c = self._conn.cursor() entries = [] if i == len(qpath) - 1: # List of albums to which belong any track from selection albidsl = self._subtreealbums(selwhere, values) albids = ','.join([str(a) for a in albidsl]) where = ' WHERE album_id in (' + albids + ') ' entries = self._direntriesforalbums(pid, where) elif i == len(qpath) - 2: # Album track list. Maybe a merged album->multiple phys albids albid = int(qpath[-1]) rawalbids = self._albids2rawalbids((albid, )) uplog("_tagsbrowsealbums: albid %s rawalbids %s" % (albid, rawalbids)) stmt = '''SELECT COUNT(docidx) FROM tracks WHERE album_id IN (%s)''' % ','.join('?' * len(rawalbids)) c.execute(stmt, rawalbids) r = c.fetchone() ntracks = int(r[0]) docidsl = self._docidsforsel(selwhere, values) stmt = '''SELECT docidx FROM tracks WHERE album_id IN (%s) AND docidx IN (%s)''' % \ (','.join('?'*len(rawalbids)), ','.join('?'*len(docidsl))) entries = self._trackentriesforstmt(stmt, rawalbids + docidsl, pid) if ntracks != len(entries): id = pid + '$' + 'showca' entries = [rcldirentry(id, pid, '>> Complete Album')] + entries elif i == len(qpath) - 3: # 'Complete album' entry # Note that minim has an additional level here, probably to # present groups or multiple groups ? The trackids ids are # like: # 0$=Composer$17738$albums$2$showca.0$hcalbum$*i13458 # I don't know what the .0 is for. # The 'hcalbum' level usually has 2 entries '>> Hide Content' # and the album title. TBD albid = int(qpath[-2]) entries = self._trackentriesforalbum(albid, pid) return entries
def search(a): msgproc.log("search: [%s]" % a) objid = a['objid'] if re.match('0\$uprcl\$', objid) is None: raise Exception("bad objid [%s]" % objid) upnps = a['origsearch'] nocache = "0" if not _ready(): entries = [ rcldirentry(objid + 'notready', objid, 'Initializing...'), ] nocache = "1" else: entries = uprclsearch.search(rclconfdir, objid, upnps, g_myprefix, httphp, pathprefix) encoded = json.dumps(entries) return {"entries": encoded, "nocache": nocache}
def browse(self, pid, flag): diridx,pthremain = self._objidtodiridx(pid) # If pthremain is set, this is pointing to 'Tag View'. Pass # the request along to the tags browser. if pthremain: if not pthremain.find('$tagview.0') == 0: raise Exception("uprclfolders: pid [%s]. bad pthremain"%pid) return uprclinit.g_trees['tags'].browseFolder(pid, flag, pthremain, self.dirpath(pid)) # If there is only one entry in root, skip it. This means that 0 # and 1 point to the same dir, but this does not seem to be an # issue if diridx == 0 and len(self._dirvec[0]) == 2: diridx = 1 #uplog("Folders browse: diridx %d content: [%s]" % # (diridx,self._dirvec[diridx])) entries = [] # The basename call is just for diridx==0 (topdirs). Remove it if # this proves a performance issue for nm,ids in self._dirvec[diridx].items(): if nm == ".." or nm == ".": continue thisdiridx = ids[0] thisdocidx = ids[1] if thisdocidx >= 0: doc = self._rcldocs[thisdocidx] else: # uplog("No doc for %s" % pid) doc = None if thisdiridx >= 0: # Skip empty directories if len(self._dirvec[thisdiridx]) == 1: continue id = self._idprefix + '$d' + str(thisdiridx) if doc and doc.albumarturi: arturi = doc.albumarturi else: arturi = self._arturifordir(thisdiridx) entries.append(rcldirentry(id, pid, os.path.basename(nm), arturi=arturi)) else: # Not a directory. docidx had better been set if thisdocidx == -1: uplog("folders:docidx -1 for non-dir entry %s"%nm) continue doc = self._rcldocs[thisdocidx] id = self._idprefix + '$i' + str(thisdocidx) e = rcldoctoentry(id, pid, self._httphp, self._pprefix, doc) if e: entries.append(e) entries.sort(key=cmpentries) # Add "Browse subtree by tags" entry if pid != self._idprefix and self._enabletags: id = pid + '$tagview.0' entries.insert(0, rcldirentry(id, pid, ">> Tag View")) return entries
def rootentries(self, pid): return [rcldirentry(pid + 'folders', pid, '[folders]'),]
def rootentries(self, pid): return [ rcldirentry(pid + 'playlists', pid, str(len(self.utidx) - 1) + ' playlists'), ]
def _tagsbrowse(self, pid, qpath, flag, path=''): uplog("tagsbrowse. pid %s qpath %s" % (pid, qpath)) # Walk the qpath, which was generated from the objid and # defines what tracks are selected and what we want to # display. E.g =Artist$21$=Date would display all distinct # dates for tracks by Artist #21. =Artist$21$=Date$48 the data # for date 48 (the numbers are indexes into the aux tables) qlen = len(qpath) selwhat = '' if path: selwhere = ' WHERE tracks.path LIKE ? ' values = [ path + '%', ] else: selwhere = '' values = [] i = 0 while i < qlen: elt = qpath[i] # Detect the special values: albums items etc. here. Their # presence changes how we process the rest (showing tracks and # albums and not dealing with other tags any more) if elt == 'albums': return self._tagsbrowsealbums(pid, qpath, i, selwhere, values) elif elt == 'items': return self._tagsbrowseitems(pid, qpath, i, selwhere, values) # '=colname'. Set the current column name, which will be used # in different ways depending if this is the last element or # not. if elt.startswith('='): col = g_tagtotable[elt[1:]] selwhere = selwhere + ' AND ' if selwhere else ' WHERE ' if i == qlen - 1: # We can only get here if the qpath ends with '=colname' # (otherwise the else branch below fetches the 2 last # elements and breaks the loop). We want to fetch all # unique values for the column inside the current selection. # e.g. artist.artist_id, artist.value selwhat = '%s.%s, %s.value' % (col, _clid(col), col) # e.g. tracks.artist_id = artist.artist_id selwhere += 'tracks.%s = %s.%s' % (_clid(col), col, _clid(col)) else: # Look at the value specified for the =xx column. The # selwhat value is only used as a flag selwhat = 'tracks.docidx' selwhere += 'tracks.%s = ?' % _clid(col) i += 1 values.append(int(qpath[i])) i += 1 entries = [] if selwhat == 'tracks.docidx': # We are displaying content for a given value of a given tag docids = self._docidsforsel(selwhere, values) albids = self._subtreealbums(selwhere, values) subqs = self._subtreetags(selwhere, values) displaytracks = True if len(albids) > 1: id = pid + '$albums' label = '%d albums' entries.append(rcldirentry(id, pid, label % len(albids))) elif len(albids) == 1 and not subqs: # Only display '>> Complete album' if not all tracks # already there. If all tracks are there, we display # the album entry (with the same id value: show album) albid = albids[0] tlist = self._trackentriesforalbum(albid, pid) id = pid + '$albums$' + str(albid) + '$showca' if len(tlist) != len(docids): entries.append(rcldirentry(id, pid, '>> Complete Album')) else: displaytracks = False el = self._direntriesforalbums( pid, "WHERE album_id = %s" % albid) el[0]['id'] = id entries.append(el[0]) if subqs: id = pid + '$items' label = '%d items' entries.append(rcldirentry(id, pid, label % len(docids))) for tt in subqs: id = pid + '$=' + tt entries.append(rcldirentry(id, pid, g_tagdisplaytag[tt])) elif displaytracks: rcldocs = uprclinit.g_trees['folders'].rcldocs() for docidx in docids: id = pid + '$*i' + str(docidx) entries.append( rcldoctoentry(id, pid, self._httphp, self._pprefix, rcldocs[docidx])) entries = sorted(entries, key=cmpentries) else: # SELECT col.col_id, col.value FROM tracks, col # WHERE tracks.col_id = col.col_id # GROUP BY tracks.col_id # ORDER BY col.value stmt = "SELECT " + selwhat + " FROM tracks, " + col + \ selwhere + \ " GROUP BY tracks." + _clid(col) + \ " ORDER BY value" uplog("tagsbrowse: executing <%s> values %s" % (stmt, values)) c = self._conn.cursor() c.execute(stmt, values) for r in c: id = pid + '$' + str(r[0]) entries.append(rcldirentry(id, pid, r[1])) return entries
def rootentries(self, pid): return [ rcldirentry(pid + 'untagged', pid, '[untagged]'), ]