Example #1
0
def album_list():
    ltype = request.values['type']

    size, offset = map(request.values.get, [ 'size', 'offset' ])
    size = int(size) if size else 10
    offset = int(offset) if offset else 0

    query = select(t.folder for t in Track)
    if ltype == 'random':
        return request.formatter('albumList', dict(
            album = [ a.as_subsonic_child(request.user) for a in query.without_distinct().random(size) ]
        ))
    elif ltype == 'newest':
        query = query.order_by(desc(Folder.created))
    elif ltype == 'highest':
        query = query.order_by(lambda f: desc(avg(f.ratings.rating)))
    elif ltype == 'frequent':
        query = query.order_by(lambda f: desc(avg(f.tracks.play_count)))
    elif ltype == 'recent':
        query = select(t.folder for t in Track if max(t.folder.tracks.last_play) is not None).order_by(lambda f: desc(max(f.tracks.last_play)))
    elif ltype == 'starred':
        query = select(s.starred for s in StarredFolder if s.user.id == request.user.id and count(s.starred.tracks) > 0)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Folder.name)
    elif ltype == 'alphabeticalByArtist':
        query = query.order_by(lambda f: f.parent.name + f.name)
    else:
        raise GenericError('Unknown search type')

    return request.formatter('albumList', dict(
        album = [ f.as_subsonic_child(request.user) for f in query.limit(size, offset) ]
    ))
Example #2
0
def list_indexes():
    musicFolderId = request.values.get("musicFolderId")
    ifModifiedSince = request.values.get("ifModifiedSince")
    if ifModifiedSince:
        ifModifiedSince = int(ifModifiedSince) / 1000

    if musicFolderId is None:
        folders = Folder.select(lambda f: f.root)[:]
    else:
        mfid = get_entity_id(Folder, musicFolderId)
        folder = Folder[mfid]
        if not folder.root:
            raise ObjectNotFound(Folder, mfid)

        folders = [folder]

    last_modif = max(map(lambda f: f.last_scan, folders))
    if ifModifiedSince is not None and last_modif < ifModifiedSince:
        return request.formatter("indexes",
                                 dict(lastModified=last_modif * 1000))

    # The XSD lies, we don't return artists but a directory structure
    artists = []
    children = []
    for f in folders:
        artists += f.children.select()[:]
        children += f.tracks.select()[:]

    indexes = dict()
    for artist in artists:
        index = artist.name[0].upper()
        if index in string.digits:
            index = "#"
        elif index not in string.ascii_letters:
            index = "?"

        if index not in indexes:
            indexes[index] = []

        indexes[index].append(artist)

    return request.formatter(
        "indexes",
        dict(
            lastModified=last_modif * 1000,
            index=[
                dict(
                    name=k,
                    artist=[
                        dict(id=str(a.id), name=a.name)
                        for a in sorted(v, key=lambda a: a.name.lower())
                    ],
                ) for k, v in sorted(indexes.items())
            ],
            child=[
                c.as_subsonic_child(request.user, request.client)
                for c in sorted(children, key=lambda t: t.sort_key())
            ],
        ),
    )
Example #3
0
def album_list():
    ltype = request.values["type"]

    size, offset = map(request.values.get, ("size", "offset"))
    size = int(size) if size else 10
    offset = int(offset) if offset else 0

    query = select(t.folder for t in Track)
    if ltype == "random":
        return request.formatter(
            "albumList",
            {
                "album": [
                    a.as_subsonic_child(request.user)
                    for a in distinct(query.random(size))
                ]
            },
        )
    elif ltype == "newest":
        query = query.sort_by(desc(Folder.created)).distinct()
    elif ltype == "highest":
        query = query.sort_by(lambda f: desc(avg(f.ratings.rating)))
    elif ltype == "frequent":
        query = query.sort_by(lambda f: desc(avg(f.tracks.play_count)))
    elif ltype == "recent":
        query = select(t.folder for t in Track
                       if max(t.folder.tracks.last_play) is not None).sort_by(
                           lambda f: desc(max(f.tracks.last_play)))
    elif ltype == "starred":
        query = select(
            s.starred for s in StarredFolder
            if s.user.id == request.user.id and count(s.starred.tracks) > 0)
    elif ltype == "alphabeticalByName":
        query = query.sort_by(Folder.name).distinct()
    elif ltype == "alphabeticalByArtist":
        query = query.sort_by(lambda f: f.parent.name + f.name)
    elif ltype == "byYear":
        startyear = int(request.values["fromYear"])
        endyear = int(request.values["toYear"])
        query = query.where(lambda t: between(t.year, min(startyear, endyear),
                                              max(startyear, endyear)))
        if endyear < startyear:
            query = query.sort_by(lambda f: desc(min(f.tracks.year)))
        else:
            query = query.sort_by(lambda f: min(f.tracks.year))
    elif ltype == "byGenre":
        genre = request.values["genre"]
        query = query.where(lambda t: t.genre == genre)
    else:
        raise GenericError("Unknown search type")

    return request.formatter(
        "albumList",
        {
            "album": [
                f.as_subsonic_child(request.user)
                for f in query.limit(size, offset)
            ]
        },
    )
Example #4
0
def album_list_id3():
    ltype = request.values['type']

    size, offset = map(request.values.get, [ 'size', 'offset' ])
    size = int(size) if size else 10
    offset = int(offset) if offset else 0

    query = Album.select()
    if ltype == 'random':
        return request.formatter('albumList2', dict(
            album = [ a.as_subsonic_album(request.user) for a in query.random(size) ]
        ))
    elif ltype == 'newest':
        query = query.order_by(lambda a: desc(min(a.tracks.created)))
    elif ltype == 'frequent':
        query = query.order_by(lambda a: desc(avg(a.tracks.play_count)))
    elif ltype == 'recent':
        query = Album.select(lambda a: max(a.tracks.last_play) is not None).order_by(lambda a: desc(max(a.tracks.last_play)))
    elif ltype == 'starred':
        query = select(s.starred for s in StarredAlbum if s.user.id == request.user.id)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Album.name)
    elif ltype == 'alphabeticalByArtist':
        query = query.order_by(lambda a: a.artist.name + a.name)
    else:
        raise GenericError('Unknown search type')

    return request.formatter('albumList2', dict(
        album = [ f.as_subsonic_album(request.user) for f in query.limit(size, offset) ]
    ))
Example #5
0
def album_list():
    ltype, size, offset = map(request.args.get, ['type', 'size', 'offset'])
    try:
        size = int(size) if size else 10
        offset = int(offset) if offset else 0
    except:
        return request.error_formatter(0, 'Invalid parameter format')

    query = session.query(Folder).filter(Folder.tracks.any())
    if ltype == 'random':
        albums = []
        count = query.count()

        if not count:
            return request.formatter({'albumList': {}})

        for _ in xrange(size):
            x = random.choice(xrange(count))
            albums.append(query.offset(x).limit(1).one())

        return request.formatter({
            'albumList': {
                'album': [a.as_subsonic_child(request.user) for a in albums]
            }
        })
    elif ltype == 'newest':
        query = query.order_by(desc(Folder.created))
    elif ltype == 'highest':
        query = query.join(RatingFolder).group_by(Folder.id).order_by(
            desc(func.avg(RatingFolder.rating)))
    elif ltype == 'frequent':
        query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by(
            desc(func.avg(Track.play_count)))
    elif ltype == 'recent':
        query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by(
            desc(func.max(Track.last_play)))
    elif ltype == 'starred':
        query = query.join(StarredFolder).join(User).filter(
            User.name == request.username)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Folder.name)
    elif ltype == 'alphabeticalByArtist':
        # this is a mess because who knows how your file structure is set up
        # with the database changes it's more difficult to get the parent of a dir
        parent = aliased(Folder)
        query = query.join(parent, Folder.parent).order_by(
            parent.name).order_by(Folder.name)
    else:
        return request.error_formatter(0, 'Unknown search type')

    return request.formatter({
        'albumList': {
            'album': [
                f.as_subsonic_child(request.user)
                for f in query.limit(size).offset(offset)
            ]
        }
    })
Example #6
0
def album_list_id3():
    ltype = request.values["type"]

    size, offset = map(request.values.get, ("size", "offset"))
    size = int(size) if size else 10
    offset = int(offset) if offset else 0

    query = Album.select()
    if ltype == "random":
        return request.formatter(
            "albumList2",
            {
                "album": [
                    a.as_subsonic_album(request.user)
                    for a in query.random(size)
                ]
            },
        )
    elif ltype == "newest":
        query = query.order_by(lambda a: desc(min(a.tracks.created)))
    elif ltype == "frequent":
        query = query.order_by(lambda a: desc(avg(a.tracks.play_count)))
    elif ltype == "recent":
        query = Album.select(
            lambda a: max(a.tracks.last_play) is not None).order_by(
                lambda a: desc(max(a.tracks.last_play)))
    elif ltype == "starred":
        query = select(s.starred for s in StarredAlbum
                       if s.user.id == request.user.id)
    elif ltype == "alphabeticalByName":
        query = query.order_by(Album.name)
    elif ltype == "alphabeticalByArtist":
        query = query.order_by(lambda a: a.artist.name + a.name)
    elif ltype == "byYear":
        startyear = int(request.values["fromYear"])
        endyear = int(request.values["toYear"])
        query = query.where(lambda a: between(min(
            a.tracks.year), min(startyear, endyear), max(startyear, endyear)))
        if endyear < startyear:
            query = query.order_by(lambda a: desc(min(a.tracks.year)))
        else:
            query = query.order_by(lambda a: min(a.tracks.year))
    elif ltype == "byGenre":
        genre = request.values["genre"]
        query = query.where(lambda a: genre in a.tracks.genre)
    else:
        raise GenericError("Unknown search type")

    return request.formatter(
        "albumList2",
        {
            "album": [
                f.as_subsonic_album(request.user)
                for f in query.limit(size, offset)
            ]
        },
    )
Example #7
0
def old_search():
    artist, album, title, anyf, count, offset, newer_than = map(
        request.values.get,
        ['artist', 'album', 'title', 'any', 'count', 'offset', 'newerThan'])

    count = int(count) if count else 20
    offset = int(offset) if offset else 0
    newer_than = int(newer_than) / 1000 if newer_than else 0
    min_date = datetime.fromtimestamp(newer_than)

    if artist:
        query = select(t.folder.parent for t in Track
                       if artist in t.folder.parent.name
                       and t.folder.parent.created > min_date)
    elif album:
        query = select(
            t.folder for t in Track
            if album in t.folder.name and t.folder.created > min_date)
    elif title:
        query = Track.select(
            lambda t: title in t.title and t.created > min_date)
    elif anyf:
        folders = Folder.select(
            lambda f: anyf in f.name and f.created > min_date)
        tracks = Track.select(
            lambda t: anyf in t.title and t.created > min_date)
        res = folders[offset:offset + count]
        fcount = folders.count()
        if offset + count > fcount:
            toff = max(0, offset - fcount)
            tend = offset + count - fcount
            res = res[:] + tracks[toff:tend][:]

        return request.formatter(
            'searchResult',
            dict(
                totalHits=folders.count() + tracks.count(),
                offset=offset,
                match=[
                    r.as_subsonic_child(request.user) if isinstance(r, Folder)
                    else r.as_subsonic_child(request.user, request.client)
                    for r in res
                ]))
    else:
        raise MissingParameter('search')

    return request.formatter(
        'searchResult',
        dict(totalHits=query.count(),
             offset=offset,
             match=[
                 r.as_subsonic_child(request.user) if isinstance(r, Folder)
                 else r.as_subsonic_child(request.user, request.client)
                 for r in query[offset:offset + count]
             ]))
Example #8
0
def lyrics():
    artist = request.values['artist']
    title = request.values['title']

    query = Track.select(lambda t: title in t.title and artist in t.artist.name)
    for track in query:
        lyrics_path = os.path.splitext(track.path)[0] + '.txt'
        if os.path.exists(lyrics_path):
            logger.debug('Found lyrics file: ' + lyrics_path)

            try:
                lyrics = read_file_as_unicode(lyrics_path)
            except UnicodeError:
                # Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
                # return no lyrics. Log it anyway.
                logger.warning('Unsupported encoding for lyrics file ' + lyrics_path)
                continue

            return request.formatter('lyrics', dict(
                artist = track.album.artist.name,
                title = track.title,
                value = lyrics
            ))

    # Create a stable, unique, filesystem-compatible identifier for the artist+title
    unique = hashlib.md5(json.dumps([x.lower() for x in (artist, title)]).encode('utf-8')).hexdigest()
    cache_key = "lyrics-{}".format(unique)

    lyrics = dict()
    try:
        lyrics = json.loads(
            zlib.decompress(
                current_app.cache.get_value(cache_key)
            ).decode('utf-8')
        )
    except (CacheMiss, zlib.error, TypeError, ValueError):
        try:
            r = requests.get("http://api.chartlyrics.com/apiv1.asmx/SearchLyricDirect",
                             params={'artist': artist, 'song': title}, timeout=5)
            root = ElementTree.fromstring(r.content)

            ns = {'cl': 'http://api.chartlyrics.com/'}
            lyrics = dict(
                artist = root.find('cl:LyricArtist', namespaces=ns).text,
                title = root.find('cl:LyricSong', namespaces=ns).text,
                value = root.find('cl:Lyric', namespaces=ns).text
            )

            current_app.cache.set(
                cache_key, zlib.compress(json.dumps(lyrics).encode('utf-8'), 9)
            )
        except requests.exceptions.RequestException as e: # pragma: nocover
            logger.warning('Error while requesting the ChartLyrics API: ' + str(e))

    return request.formatter('lyrics', lyrics)
Example #9
0
def album_list():
    ltype, size, offset = map(request.args.get, ['type', 'size', 'offset'])
    try:
        size = int(size) if size else 10
        offset = int(offset) if offset else 0
    except:
        return request.error_formatter(0, 'Invalid parameter format')

    query = store.find(Folder, Track.folder_id == Folder.id)
    if ltype == 'random':
        albums = []
        count = query.count()

        if not count:
            return request.formatter({'albumList': {}})

        for _ in xrange(size):
            x = random.choice(xrange(count))
            albums.append(query[x])

        return request.formatter({
            'albumList': {
                'album': [a.as_subsonic_child(request.user) for a in albums]
            }
        })
    elif ltype == 'newest':
        query = query.order_by(Desc(Folder.created)).config(distinct=True)
    elif ltype == 'highest':
        query = query.find(RatingFolder.rated_id == Folder.id).group_by(
            Folder.id).order_by(Desc(Avg(RatingFolder.rating)))
    elif ltype == 'frequent':
        query = query.group_by(Folder.id).order_by(Desc(Avg(Track.play_count)))
    elif ltype == 'recent':
        query = query.group_by(Folder.id).order_by(Desc(Max(Track.last_play)))
    elif ltype == 'starred':
        query = query.find(StarredFolder.starred_id == Folder.id,
                           User.id == StarredFolder.user_id,
                           User.name == request.username)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Folder.name).config(distinct=True)
    elif ltype == 'alphabeticalByArtist':
        parent = ClassAlias(Folder)
        query = query.find(Folder.parent_id == parent.id).order_by(
            parent.name, Folder.name).config(distinct=True)
    else:
        return request.error_formatter(0, 'Unknown search type')

    return request.formatter({
        'albumList': {
            'album': [
                f.as_subsonic_child(request.user)
                for f in query[offset:offset + size]
            ]
        }
    })
Example #10
0
def lyrics():
    artist = request.values['artist']
    title = request.values['title']

    query = Track.select(lambda t: title in t.title and artist in t.artist.name)
    for track in query:
        lyrics_path = os.path.splitext(track.path)[0] + '.txt'
        if os.path.exists(lyrics_path):
            logger.debug('Found lyrics file: ' + lyrics_path)

            try:
                lyrics = read_file_as_unicode(lyrics_path)
            except UnicodeError:
                # Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
                # return no lyrics. Log it anyway.
                logger.warning('Unsupported encoding for lyrics file ' + lyrics_path)
                continue

            return request.formatter('lyrics', dict(
                artist = track.album.artist.name,
                title = track.title,
                value = lyrics
            ))

    # Create a stable, unique, filesystem-compatible identifier for the artist+title
    unique = hashlib.md5(json.dumps([x.lower() for x in (artist, title)]).encode('utf-8')).hexdigest()
    cache_key = "lyrics-{}".format(unique)

    lyrics = dict()
    try:
        lyrics = json.loads(
            zlib.decompress(
                current_app.cache.get_value(cache_key)
            ).decode('utf-8')
        )
    except (CacheMiss, zlib.error, TypeError, ValueError):
        try:
            r = requests.get("http://api.chartlyrics.com/apiv1.asmx/SearchLyricDirect",
                             params={'artist': artist, 'song': title}, timeout=5)
            root = ElementTree.fromstring(r.content)

            ns = {'cl': 'http://api.chartlyrics.com/'}
            lyrics = dict(
                artist = root.find('cl:LyricArtist', namespaces=ns).text,
                title = root.find('cl:LyricSong', namespaces=ns).text,
                value = root.find('cl:Lyric', namespaces=ns).text
            )

            current_app.cache.set(
                cache_key, zlib.compress(json.dumps(lyrics).encode('utf-8'), 9)
            )
        except requests.exceptions.RequestException as e: # pragma: nocover
            logger.warning('Error while requesting the ChartLyrics API: ' + str(e))

    return request.formatter('lyrics', lyrics)
Example #11
0
def album_list_id3():
    ltype, size, offset = map(request.args.get, ['type', 'size', 'offset'])
    try:
        size = int(size) if size else 10
        offset = int(offset) if offset else 0
    except:
        return request.error_formatter(0, 'Invalid parameter format')

    query = store.find(Album)
    if ltype == 'random':
        albums = []
        count = query.count()

        if not count:
            return request.formatter({'albumList2': {}})

        for _ in xrange(size):
            x = random.choice(xrange(count))
            albums.append(query[x])

        return request.formatter({
            'albumList2': {
                'album': [a.as_subsonic_album(request.user) for a in albums]
            }
        })
    elif ltype == 'newest':
        query = query.find(Track.album_id == Album.id).group_by(
            Album.id).order_by(Desc(Min(Track.created)))
    elif ltype == 'frequent':
        query = query.find(Track.album_id == Album.id).group_by(
            Album.id).order_by(Desc(Avg(Track.play_count)))
    elif ltype == 'recent':
        query = query.find(Track.album_id == Album.id).group_by(
            Album.id).order_by(Desc(Max(Track.last_play)))
    elif ltype == 'starred':
        query = query.find(StarredAlbum.starred_id == Album.id,
                           User.id == StarredAlbum.user_id,
                           User.name == request.username)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Album.name)
    elif ltype == 'alphabeticalByArtist':
        query = query.find(Artist.id == Album.artist_id).order_by(
            Artist.name, Album.name)
    else:
        return request.error_formatter(0, 'Unknown search type')

    return request.formatter({
        'albumList2': {
            'album': [
                f.as_subsonic_album(request.user)
                for f in query[offset:offset + size]
            ]
        }
    })
Example #12
0
def lyrics():
    artist, title = map(request.args.get, ['artist', 'title'])
    if not artist:
        return request.error_formatter(10, 'Missing artist parameter')
    if not title:
        return request.error_formatter(10, 'Missing title parameter')

    query = session.query(Track).join(Album, Artist).filter(
        func.lower(Track.title) == title.lower()
        and func.lower(Artist.name) == artist.lower())
    for track in query:
        lyrics_path = os.path.splitext(track.path)[0] + '.txt'
        if os.path.exists(lyrics_path):
            app.logger.debug('Found lyrics file: ' + lyrics_path)

            try:
                lyrics = read_file_as_unicode(lyrics_path)
            except UnicodeError:
                # Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
                # return no lyrics. Log it anyway.
                app.logger.warn('Unsupported encoding for lyrics file ' +
                                lyrics_path)
                continue

            return request.formatter({
                'lyrics': {
                    'artist': track.album.artist.name,
                    'title': track.title,
                    '_value_': lyrics
                }
            })

    try:
        r = requests.get(
            "http://api.chartlyrics.com/apiv1.asmx/SearchLyricDirect",
            params={
                'artist': artist,
                'song': title
            })
        root = ElementTree.fromstring(r.content)

        ns = {'cl': 'http://api.chartlyrics.com/'}
        return request.formatter({
            'lyrics': {
                'artist': root.find('cl:LyricArtist', namespaces=ns).text,
                'title': root.find('cl:LyricSong', namespaces=ns).text,
                '_value_': root.find('cl:Lyric', namespaces=ns).text
            }
        })
    except requests.exceptions.RequestException, e:
        app.logger.warn('Error while requesting the ChartLyrics API: ' +
                        str(e))
Example #13
0
def album_list_id3():
    ltype, size, offset = map(request.args.get, ['type', 'size', 'offset'])
    try:
        size = int(size) if size else 10
        offset = int(offset) if offset else 0
    except:
        return request.error_formatter(0, 'Invalid parameter format')

    query = session.query(Album)
    if ltype == 'random':
        albums = []
        count = query.count()

        if not count:
            return request.formatter({'albumList2': {}})

        for _ in xrange(size):
            x = random.choice(xrange(count))
            albums.append(query.offset(x).limit(1).one())

        return request.formatter({
            'albumList2': {
                'album': [a.as_subsonic_album(request.user) for a in albums]
            }
        })
    elif ltype == 'newest':
        query = query.join(Track, Album.tracks).group_by(Album.id).order_by(
            desc(func.min(Track.created)))
    elif ltype == 'frequent':
        query = query.join(Track, Album.tracks).group_by(Album.id).order_by(
            desc(func.avg(Track.play_count)))
    elif ltype == 'recent':
        query = query.join(Track, Album.tracks).group_by(Album.id).order_by(
            desc(func.max(Track.last_play)))
    elif ltype == 'starred':
        query = query.join(StarredAlbum).join(User).filter(
            User.name == request.username)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Album.name)
    elif ltype == 'alphabeticalByArtist':
        query = query.join(Artist).order_by(Artist.name).order_by(Album.name)
    else:
        return request.error_formatter(0, 'Unknown search type')

    return request.formatter({
        'albumList2': {
            'album': [
                f.as_subsonic_album(request.user)
                for f in query.limit(size).offset(offset)
            ]
        }
    })
Example #14
0
def list_indexes():
    musicFolderId = request.values.get('musicFolderId')
    ifModifiedSince = request.values.get('ifModifiedSince')
    if ifModifiedSince:
        ifModifiedSince = int(ifModifiedSince) / 1000

    if musicFolderId is None:
        folders = Folder.select(lambda f: f.root)[:]
    else:
        mfid = uuid.UUID(musicFolderId)
        folder = Folder[mfid]
        if not folder.root:
            raise ObjectNotFound(Folder, mfid)

        folders = [ folder ]

    last_modif = max(map(lambda f: f.last_scan, folders))
    if ifModifiedSince is not None and last_modif < ifModifiedSince:
        return request.formatter('indexes', dict(lastModified = last_modif * 1000))

    # The XSD lies, we don't return artists but a directory structure
    artists = []
    children = []
    for f in folders:
        artists += f.children.select()[:]
        children += f.tracks.select()[:]

    indexes = dict()
    for artist in artists:
        index = artist.name[0].upper()
        if index in string.digits:
            index = '#'
        elif index not in string.ascii_letters:
            index = '?'

        if index not in indexes:
            indexes[index] = []

        indexes[index].append(artist)

    return request.formatter('indexes', dict(
        lastModified = last_modif * 1000,
        index = [ dict(
            name = k,
            artist = [ dict(
                id = str(a.id),
                name = a.name
            ) for a in sorted(v, key = lambda a: a.name.lower()) ]
        ) for k, v in sorted(indexes.items()) ],
        child = [ c.as_subsonic_child(request.user, request.client) for c in sorted(children, key = lambda t: t.sort_key()) ]
    ))
Example #15
0
def album_list():
    ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ])
    if not ltype:
        return request.error_formatter(10, 'Missing type')
    try:
        size = int(size) if size else 10
        offset = int(offset) if offset else 0
    except:
        return request.error_formatter(0, 'Invalid parameter format')

    query = store.find(Folder, Track.folder_id == Folder.id)
    if ltype == 'random':
        albums = []
        count = query.count()

        if not count:
            return request.formatter({ 'albumList': {} })

        for _ in xrange(size):
            x = random.choice(xrange(count))
            albums.append(query[x])

        return request.formatter({
            'albumList': {
                'album': [ a.as_subsonic_child(request.user) for a in albums ]
            }
        })
    elif ltype == 'newest':
        query = query.order_by(Desc(Folder.created)).config(distinct = True)
    elif ltype == 'highest':
        query = query.find(RatingFolder.rated_id == Folder.id).group_by(Folder.id).order_by(Desc(Avg(RatingFolder.rating)))
    elif ltype == 'frequent':
        query = query.group_by(Folder.id).order_by(Desc(Avg(Track.play_count)))
    elif ltype == 'recent':
        query = query.group_by(Folder.id).order_by(Desc(Max(Track.last_play)))
    elif ltype == 'starred':
        query = query.find(StarredFolder.starred_id == Folder.id, User.id == StarredFolder.user_id, User.name == request.username)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Folder.name).config(distinct = True)
    elif ltype == 'alphabeticalByArtist':
        parent = ClassAlias(Folder)
        query = query.find(Folder.parent_id == parent.id).order_by(parent.name, Folder.name).config(distinct = True)
    else:
        return request.error_formatter(0, 'Unknown search type')

    return request.formatter({
        'albumList': {
            'album': [ f.as_subsonic_child(request.user) for f in query[offset:offset+size] ]
        }
    })
Example #16
0
def album_list():
	ltype, size, offset = map(request.args.get, [ 'type', 'size', 'offset' ])
	try:
		size = int(size) if size else 10
		offset = int(offset) if offset else 0
	except:
		return request.error_formatter(0, 'Invalid parameter format')

	query = session.query(Folder).filter(Folder.tracks.any())
	if ltype == 'random':
		albums = []
		count = query.count()

		if not count:
			return request.formatter({ 'albumList': {} })

		for _ in xrange(size):
			x = random.choice(xrange(count))
			albums.append(query.offset(x).limit(1).one())

		return request.formatter({
			'albumList': {
				'album': [ a.as_subsonic_child(request.user) for a in albums ]
			}
		})
	elif ltype == 'newest':
		query = query.order_by(desc(Folder.created))
	elif ltype == 'highest':
		query = query.join(RatingFolder).group_by(Folder.id).order_by(desc(func.avg(RatingFolder.rating)))
	elif ltype == 'frequent':
		query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by(desc(func.avg(Track.play_count)))
	elif ltype == 'recent':
		query = query.join(Track, Folder.tracks).group_by(Folder.id).order_by(desc(func.max(Track.last_play)))
	elif ltype == 'starred':
		query = query.join(StarredFolder).join(User).filter(User.name == request.username)
	elif ltype == 'alphabeticalByName':
		query = query.order_by(Folder.name)
	elif ltype == 'alphabeticalByArtist':
		# this is a mess because who knows how your file structure is set up
		# with the database changes it's more difficult to get the parent of a dir
		parent = aliased(Folder)
		query = query.join(parent, Folder.parent).order_by(parent.name).order_by(Folder.name)
	else:
		return request.error_formatter(0, 'Unknown search type')

	return request.formatter({
		'albumList': {
			'album': [ f.as_subsonic_child(request.user) for f in query.limit(size).offset(offset) ]
		}
	})
Example #17
0
def scrobble_view():
    """Add song to last.fm

        id	Yes		A string which uniquely identifies the file to scrobble.
        time	No		(Since 1.8.0) The time (in milliseconds since 1 Jan 1970) at which the song was listened to.
        submission	No	True	Whether this is a "submission" or a "now playing" notification.


    """
    from mediamanager.scrobble import q
    (u, p, v, c, f, callback) = map(
        request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback'])
    (eid, ts, submission) = map(
        request.args.get, ['id', 'time', 'submission'])
    assert eid, "Missing song id"

    log.info("Retrieving scrobbling credentials")
    lastfm_user = app.iposonic.get_users(MediaManager.uuid(u))
    log.info("Scobbling credentials: %s" % lastfm_user)
    # get song info and append timestamp
    info = app.iposonic.get_entry_by_id(eid)
    info.update({'timestamp': int(time.time())})
    q.put(({
        'username': lastfm_user.get('scrobbleUser'),
        'password': lastfm_user.get('scrobblePassword')}, info))

    return request.formatter({})
Example #18
0
def search_id3():
	query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
			request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])

	try:
		artist_count = int(artist_count) if artist_count else 20
		artist_offset = int(artist_offset) if artist_offset else 0
		album_count = int(album_count) if album_count else 20
		album_offset = int(album_offset) if album_offset else 0
		song_count = int(song_count) if song_count else 20
		song_offset = int(song_offset) if song_offset else 0
	except:
		return request.error_formatter(0, 'Invalid parameter')

	if not query:
		return request.error_formatter(10, 'Missing query parameter')

	artist_query = session.query(Artist).filter(Artist.name.contains(query)).slice(artist_offset, artist_offset + artist_count)
	album_query = session.query(Album).filter(Album.name.contains(query)).slice(album_offset, album_offset + album_count)
	song_query = session.query(Track).filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count)

	return request.formatter({ 'searchResult2': {
		'artist': [ a.as_subsonic_artist(request.user) for a in artist_query ],
		'album': [ a.as_subsonic_album(request.user) for a in album_query ],
		'song': [ t.as_subsonic_child(request.user) for t in song_query ]
		}})
Example #19
0
def random_songs(typed):
    ok, size = check_parameter(request,
                               'size',
                               fct=lambda val: int(val) if val else 10)
    if not ok:
        return False, size
    size = min(size, 50)
    fromYear = request.args.get('fromYear')
    toYear = request.args.get('toYear')
    genre = request.args.get('genre')

    fltr = list(get_filter(fromYear=fromYear, toYear=toYear, genre=genre))
    count = typed.counttracks(lambda query: query.filter(*fltr))

    def gen():
        if count > 0:
            for _ in range(size):
                x = random.choice(range(count))
                yield typed.gettrackinfo(ffilter=lambda query: query.filter(
                    *fltr).offset(x).limit(1))

    return request.formatter({
        'randomSongs': {
            'song': [format_track(track, child=True) for track in gen()]
        }
    })
Example #20
0
def set_formatter():
    if not request.path.startswith('/rest/'):
        return
    """Return a function to create the response."""
    (f, callback) = map(request.values.get, ['f', 'callback'])
    if f == 'jsonp':
        # Some clients (MiniSub, Perisonic) set f to jsonp without callback for streamed data
        if not callback and request.endpoint not in [
                'stream_media', 'cover_art'
        ]:
            return ResponseHelper.responsize_json(
                {'error': {
                    'code': 10,
                    'message': 'Missing callback'
                }},
                error=True), 400
        request.formatter = lambda x, **kwargs: ResponseHelper.responsize_jsonp(
            x, callback, kwargs)
    elif f == "json":
        request.formatter = ResponseHelper.responsize_json
    else:
        request.formatter = ResponseHelper.responsize_xml

    request.error_formatter = lambda code, msg: request.formatter(
        {'error': {
            'code': code,
            'message': msg
        }}, error=True)
Example #21
0
def search_id3():
	query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
		request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])

	try:
		artist_count = int(artist_count) if artist_count else 20
		artist_offset = int(artist_offset) if artist_offset else 0
		album_count = int(album_count) if album_count else 20
		album_offset = int(album_offset) if album_offset else 0
		song_count = int(song_count) if song_count else 20
		song_offset = int(song_offset) if song_offset else 0
	except:
		return request.error_formatter(0, 'Invalid parameter')

	if not query:
		return request.error_formatter(10, 'Missing query parameter')

	artist_query = Artist.query.filter(Artist.name.contains(query)).slice(artist_offset, artist_offset + artist_count)
	album_query = Album.query.filter(Album.name.contains(query)).slice(album_offset, album_offset + album_count)
	song_query = Track.query.filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count)

	return request.formatter({ 'searchResult2': {
		'artist': [ a.as_subsonic_artist(request.user) for a in artist_query ],
		'album': [ a.as_subsonic_album(request.user) for a in album_query ],
		'song': [ t.as_subsonic_child(request.user) for t in song_query ]
	}})
Example #22
0
def get_now_playing_view():
    """TODO: save timestamp and song duration of every stream.view request

        xml response:
            <nowPlaying>
                <entry username="******"
                    minutesAgo="12"
                    playerId="2"
                    ... # all media properties />

                <entry username="******"
                    minutesAgo="1"
                    playerId="4"
                    playerName="Kitchen"
                    ... # all media properties
                />
            </nowPlaying>
        """
    (u, p, v, c, f, callback) = map(
        request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback'])
    user = app.iposonic.get_users(eid=MediaManager.uuid(u))
    assert user.get('nowPlaying'), "Nothing playing now..."

    song = app.iposonic.get_songs(eid=user.get('nowPlaying'))
    song.update({'username': u})

    return request.formatter({'nowPlaying': {'entry': song}})
Example #23
0
def new_search():
	query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
		request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])

	try:
		artist_count =  int(artist_count)  if artist_count  else 20
		artist_offset = int(artist_offset) if artist_offset else 0
		album_count =   int(album_count)   if album_count   else 20
		album_offset =  int(album_offset)  if album_offset  else 0
		song_count =    int(song_count)    if song_count    else 20
		song_offset =   int(song_offset)   if song_offset   else 0
	except:
		return request.error_formatter(0, 'Invalid parameter')

	if not query:
		return request.error_formatter(10, 'Missing query parameter')

	parent = ClassAlias(Folder)
	artist_query = store.find(parent, Folder.parent_id == parent.id, Track.folder_id == Folder.id, parent.name.contains_string(query)).config(distinct = True, offset = artist_offset, limit = artist_count)
	album_query = store.find(Folder, Track.folder_id == Folder.id, Folder.name.contains_string(query)).config(distinct = True, offset = album_offset, limit = album_count)
	song_query = store.find(Track, Track.title.contains_string(query))[song_offset : song_offset + song_count]

	return request.formatter({ 'searchResult2': {
		'artist': [ { 'id': str(a.id), 'name': a.name } for a in artist_query ],
		'album': [ f.as_subsonic_child(request.user) for f in album_query ],
		'song': [ t.as_subsonic_child(request.user) for t in song_query ]
	}})
Example #24
0
def unstar():
	id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ])

	def try_unstar(ent, eid):
		try:
			uid = uuid.UUID(eid)
		except:
			return request.error_formatter(0, 'Invalid id')

		store.find(ent, ent.user_id == request.user.id, ent.starred_id == uid).remove()
		return None

	for eid in id:
		err = try_unstar(StarredTrack, eid)
		if err:
			return err
		err = try_unstar(StarredFolder, eid)
		if err:
			return err

	for alId in albumId:
		err = try_unstar(StarredAlbum, alId)
		if err:
			return err

	for arId in artistId:
		err = try_unstar(StarredArtist, arId)
		if err:
			return err

	store.commit()
	return request.formatter({})
Example #25
0
def list_artists():
    # According to the API page, there are no parameters?
    indexes = {}
    for artist in store.find(Artist):
        index = artist.name[0].upper() if artist.name else '?'
        if index in map(str, xrange(10)):
            index = '#'
        elif index not in string.letters:
            index = '?'

        if index not in indexes:
            indexes[index] = []

        indexes[index].append(artist)

    return request.formatter({
        'artists': {
            'index': [{
                'name':
                k,
                'artist': [
                    a.as_subsonic_artist(request.user)
                    for a in sorted(v, key=lambda a: a.name.lower())
                ]
            } for k, v in sorted(indexes.iteritems())]
        }
    })
Example #26
0
def get_playlists_view():
    """ response xml:
        <playlists>
                <playlist id="15" name="Some random songs" comment="Just something I tossed together" owner="admin" public="false" songCount="6" duration="1391" created="2012-04-17T19:53:44">
                    <allowedUser>sindre</allowedUser>
                    <allowedUser>john</allowedUser>
                </playlist>
                <playlist id="16" name="More random songs" comment="No comment" owner="admin" public="true" songCount="5" duration="1018" created="2012-04-17T19:55:49"/>
            </playlists>

        response jsonp:
            {playlists: { playlist : [
                {   id : ,
                    name: ,
                    comment: ,
                    owner: ,
                    public: ,
                    songCount:,
                    duration: ,
                    created:,
                },
                {   id, name, comment, owner, public, allowedUser: [
                    'jon',
                    'mary'
                    ] }
                ]
            }}
    """
    (u, p, v, c, f, callback) = map(
        request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback'])

    playlists = app.iposonic.get_playlists_static()

    playlists.extend(app.iposonic.get_playlists())
    return request.formatter({'status': 'ok', 'playlists': {'playlist': playlists}})
Example #27
0
def rate():
	id, rating = map(request.args.get, [ 'id', 'rating' ])
	if not id or not rating:
		return request.error_formatter(10, 'Missing parameter')

	try:
		uid = uuid.UUID(id)
		rating = int(rating)
	except:
		return request.error_formatter(0, 'Invalid parameter')

	if not rating in xrange(6):
		return request.error_formatter(0, 'rating must be between 0 and 5 (inclusive)')

	if rating == 0:
		RatingTrack.query.filter(RatingTrack.user_id == request.user.id).filter(RatingTrack.rated_id == uid).delete()
		RatingFolder.query.filter(RatingFolder.user_id == request.user.id).filter(RatingFolder.rated_id == uid).delete()
	else:
		rated = Track.query.get(uid)
		rating_ent = RatingTrack
		if not rated:
			rated = Folder.query.get(uid)
			rating_ent = RatingFolder
			if not rated:
				return request.error_formatter(70, 'Unknown id')

		rating_info = rating_ent.query.get((request.user.id, uid))
		if rating_info:
			rating_info.rating = rating
		else:
			session.add(rating_ent(user = request.user, rated = rated, rating = rating))

	session.commit()
	return request.formatter({})
Example #28
0
def get_starred():
    folders = store.find(StarredFolder, StarredFolder.user_id == User.id,
                         User.name == request.username)

    return request.formatter({
        'starred': {
            'artist': [{
                'id': str(sf.starred_id),
                'name': sf.starred.name
            } for sf in folders.find(
                Folder.parent_id == StarredFolder.starred_id, Track.folder_id
                == Folder.id).config(distinct=True)],
            'album': [
                sf.starred.as_subsonic_child(request.user)
                for sf in folders.find(
                    Track.folder_id == StarredFolder.starred_id).config(
                        distinct=True)
            ],
            'song': [
                st.starred.as_subsonic_child(request.user)
                for st in store.find(StarredTrack, StarredTrack.user_id ==
                                     User.id, User.name == request.username)
            ]
        }
    })
Example #29
0
def list_artists():
	# According to the API page, there are no parameters?
	indexes = {}

        # Optimized query instead of using backrefs, is there a way to speed up the backref?
	c = session.query(Album.artist_id, func.count(Album.artist_id).label('c')).group_by(Album.artist_id).subquery(name='c')
	for artist in session.query(Artist.name, Artist.id, c.c.c.label('albums')).join(c).order_by(Artist.name).all():

		index = artist.name[0].upper() if artist.name else '?'

		if index in map(str, xrange(10)):
			index = '#'
		elif index not in string.letters:
			index = '?'

		if index not in indexes:
			indexes[index] = []

		indexes[index].append(artist)

	return request.formatter({
		'artists': {
			'index': [ {
				'name': k,
				'artist': [ {
				    'id': a.id,
				    'name': a.name.strip(),
				    'albumCount': a.albums
				} for a in v ]
				} for k, v in sorted(indexes.iteritems()) ]
			}
		})
Example #30
0
def list_folders():
    return request.formatter('musicFolders', dict(
        musicFolder = [ dict(
            id = str(f.id),
            name = f.name
        ) for f in Folder.select(lambda f: f.root).order_by(Folder.name) ]
    ))
Example #31
0
def create_user_view():
    """Create an user getting info from GET variables.

        TODO get with post too
    """
    (u, p, v, c, f, callback) = map(
        request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback'])

    (un, pw, email, scrobbleUser, scrobblePassword) = map(request.args.get, [
                                                          'x',
                                                          'password',
                                                          'email',
                                                          'scrobbleUser',
                                                          'scrobblePassword'
                                                          ])
    new_user = {
        'username': un,
        'password': pw,
        'email': email,
        'scrobbleUser': scrobbleUser,
        'scrobblePassword': scrobblePassword
    }
    print("user: %s " % new_user)
    app.iposonic.add_user(new_user)
    return request.formatter({})
Example #32
0
def star_view():
    (u, p, v, c, f, callback) = map(
        request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback'])
    (eid, rating) = map(request.args.get, ['id', 'rating'])
    if not eid:
        raise SubsonicMissingParameterException(
            'id', sys._getframe().f_code.co_name)
    app.iposonic.update_entry(
        eid, {'starred': time.strftime("%Y-%m-%dT%H:%M:%S")})

    # XXX example code to be added to Iposonic
    # for managing user-based media tagging
    # like starred.
    # Going this way may need to really choiche ONE db
    # because we'll multiply data (eg. #items x #users)
    #usermedia = app.iposonic.db.UserMedia('mock_user', eid)
    #usermedia.update( {
    #    'starred': time.strftime("%Y-%m-%dT%H:%M:%S"),
    #    'eid': "%s:%s" % ('mock',eid),
    #    'mid' : eid,
    #    'uid' : 'mock'
    #    } )
    app.iposonic.create_entry(usermedia)

    return request.formatter({})
Example #33
0
def new_search():
	query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
		request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])

	try:
		artist_count = int(artist_count) if artist_count else 20
		artist_offset = int(artist_offset) if artist_offset else 0
		album_count = int(album_count) if album_count else 20
		album_offset = int(album_offset) if album_offset else 0
		song_count = int(song_count) if song_count else 20
		song_offset = int(song_offset) if song_offset else 0
	except:
		return request.error_formatter(0, 'Invalid parameter')

	if not query:
		return request.error_formatter(10, 'Missing query parameter')

	artist_query = Folder.query.filter(~ Folder.tracks.any(), Folder.name.contains(query)).slice(artist_offset, artist_offset + artist_count)
	album_query = Folder.query.filter(Folder.tracks.any(), Folder.name.contains(query)).slice(album_offset, album_offset + album_count)
	song_query = Track.query.filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count)

	return request.formatter({ 'searchResult2': {
		'artist': [ { 'id': str(a.id), 'name': a.name } for a in artist_query ],
		'album': [ f.as_subsonic_child(request.user) for f in album_query ],
		'song': [ t.as_subsonic_child(request.user) for t in song_query ]
	}})
Example #34
0
def list_folders():
    return request.formatter('musicFolders', dict(
        musicFolder = [ dict(
            id = str(f.id),
            name = f.name
        ) for f in Folder.select(lambda f: f.root).order_by(Folder.name) ]
    ))
Example #35
0
def get_now_playing_view():
    """TODO: save timestamp and song duration of every stream.view request

        xml response:
            <nowPlaying>
                <entry username="******"
                    minutesAgo="12"
                    playerId="2"
                    ... # all media properties />

                <entry username="******"
                    minutesAgo="1"
                    playerId="4"
                    playerName="Kitchen"
                    ... # all media properties
                />
            </nowPlaying>
        """
    (u, p, v, c, f, callback) = map(request.args.get,
                                    ['u', 'p', 'v', 'c', 'f', 'callback'])
    user = app.iposonic.get_users(eid=MediaManager.uuid(u))
    assert user.get('nowPlaying'), "Nothing playing now..."

    song = app.iposonic.get_songs(eid=user.get('nowPlaying'))
    song.update({'username': u})

    return request.formatter({'nowPlaying': {'entry': song}})
Example #36
0
def new_search():
	query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
	request.args.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])

	try:
		artist_count = int(artist_count) if artist_count else 20
		artist_offset = int(artist_offset) if artist_offset else 0
		album_count = int(album_count) if album_count else 20
		album_offset = int(album_offset) if album_offset else 0
		song_count = int(song_count) if song_count else 20
		song_offset = int(song_offset) if song_offset else 0
	except:
		return request.error_formatter(0, 'Invalid parameter')

	if not query:
		return request.error_formatter(10, 'Missing query parameter')

	artist_query = session.query(Folder).filter(~ Folder.tracks.any(), Folder.path.contains(query)).slice(artist_offset, artist_offset + artist_count)
	album_query = session.query(Folder).filter(Folder.tracks.any(), Folder.path.contains(query)).slice(album_offset, album_offset + album_count)
	song_query = sesion.query(Track).filter(Track.title.contains(query)).slice(song_offset, song_offset + song_count)

	return request.formatter({ 'searchResult2': {
		'artist': [ { 'id': a.id, 'name': a.name } for a in artist_query ],
		'album': [ f.as_subsonic_child(request.user) for f in album_query ],
		'song': [ t.as_subsonic_child(request.user) for t in song_query ]
	}})
Example #37
0
def update_playlist():
    status, res = get_entity(request, Playlist, 'playlistId')
    if not status:
        return res

    if res.user_id != request.user.id and not request.user.admin:
        return request.error_formatter(50, "You're not allowed to delete a playlist that isn't yours")

    playlist = res
    name, comment, public = map(request.values.get, [ 'name', 'comment', 'public' ])
    to_add, to_remove = map(request.values.getlist, [ 'songIdToAdd', 'songIndexToRemove' ])
    try:
        to_add = map(uuid.UUID, to_add)
        to_remove = map(int, to_remove)
    except:
        return request.error_formatter(0, 'Invalid parameter')

    if name:
        playlist.name = name
    if comment:
        playlist.comment = comment
    if public:
        playlist.public = public in (True, 'True', 'true', 1, '1')

    for sid in to_add:
        track = store.get(Track, sid)
        if not track:
            return request.error_formatter(70, 'Unknown song')
        playlist.add(track)

    playlist.remove_at_indexes(to_remove)

    store.commit()
    return request.formatter({})
Example #38
0
def music_directory(typed):
    eid = request.args.get('id')
    cid = clean_id(eid)
    if is_artist_id(eid):
        dirlist = typed.listalbumsbyartists(
            lambda query: query.filter(Artist.id == cid))
        children = dirlist[0].albums
        format_directory_id = format_artist_id
        format_child = format_album
    elif is_album_id(eid):
        dirlist = typed.listtracksbyalbums(
            lambda query: query.filter(Album.id == cid))
        children = dirlist[0].tracks
        format_directory_id = format_album_id
        format_child = format_track
    else:
        return request.error_formatter(10, 'Missing or invalid id')

    return request.formatter({
        'directory': {
            'id': format_directory_id(dirlist[0].id),
            'name': dirlist[0].name,
            'child': [format_child(child, child=True) for child in children]
        }
    })
Example #39
0
def rand_songs():
    size = request.values.get("size", "10")
    genre, fromYear, toYear, musicFolderId = map(
        request.values.get, ["genre", "fromYear", "toYear", "musicFolderId"])

    size = int(size) if size else 10
    fromYear = int(fromYear) if fromYear else None
    toYear = int(toYear) if toYear else None
    fid = None
    if musicFolderId:
        try:
            fid = int(musicFolderId)
        except ValueError:
            raise ValueError("Invalid folder ID")

    query = Track.select()
    if fromYear:
        query = query.filter(lambda t: t.year >= fromYear)
    if toYear:
        query = query.filter(lambda t: t.year <= toYear)
    if genre:
        query = query.filter(lambda t: t.genre == genre)
    if fid:
        if not Folder.exists(id=fid, root=True):
            raise NotFound("Folder")

        query = query.filter(lambda t: t.root_folder.id == fid)

    return request.formatter(
        "randomSongs",
        dict(song=[
            t.as_subsonic_child(request.user, request.client)
            for t in query.without_distinct().random(size)
        ]),
    )
Example #40
0
def show_directory():
    status, res = get_entity(request, Folder)
    if not status:
        return res

    res.tracks = [t for t in res.tracks if os.path.isfile(t.path)]

    directory = {
        'id':
        res.id,
        'name':
        res.name,
        'child':
        [f.as_subsonic_child(request.user) for f in res.get_children()] + [
            t.as_subsonic_child(request.user)
            for t in sorted(res.tracks, key=lambda t: t.sort_key())
        ]
    }
    if not res.root:
        parent = session.query(Folder).with_entities(Folder.id) \
         .filter(Folder.path.like(res.path[:len(res.path)-len(res.name)-1])) \
         .order_by(func.length(Folder.path).desc()).first()
        if parent:
            directory['parent'] = parent.id

    return request.formatter({'directory': directory})
Example #41
0
def list_artists():
    # According to the API page, there are no parameters?
    indexes = dict()
    pattern = build_ignored_articles_pattern()
    for artist in Artist.select():
        name = artist.name or "?"
        if pattern:
            name = re.sub(pattern, "", name, flags=re.I)
        index = name[0].upper()
        if index in string.digits:
            index = "#"
        elif index not in string.ascii_letters:
            index = "?"

        if index not in indexes:
            indexes[index] = []

        indexes[index].append((artist, name))

    return request.formatter(
        "artists",
        dict(
            ignoredArticles=ignored_articles_str(),
            index=[
                dict(
                    name=k,
                    artist=[
                        a.as_subsonic_artist(request.user)
                        for a, _ in sorted(v, key=lambda t: t[1].lower())
                    ],
                ) for k, v in sorted(indexes.items())
            ],
        ),
    )
Example #42
0
def search_id3():
    query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
        request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])

    try:
        artist_count =  int(artist_count)  if artist_count  else 20
        artist_offset = int(artist_offset) if artist_offset else 0
        album_count =   int(album_count)   if album_count   else 20
        album_offset =  int(album_offset)  if album_offset  else 0
        song_count =    int(song_count)    if song_count    else 20
        song_offset =   int(song_offset)   if song_offset   else 0
    except:
        return request.error_formatter(0, 'Invalid parameter')

    if not query:
        return request.error_formatter(10, 'Missing query parameter')

    artist_query = store.find(Artist, Artist.name.contains_string(query))[artist_offset : artist_offset + artist_count]
    album_query = store.find(Album, Album.name.contains_string(query))[album_offset : album_offset + album_count]
    song_query = store.find(Track, Track.title.contains_string(query))[song_offset : song_offset + song_count]

    return request.formatter({ 'searchResult3': {
        'artist': [ a.as_subsonic_artist(request.user) for a in artist_query ],
        'album': [ a.as_subsonic_album(request.user) for a in album_query ],
        'song': [ t.as_subsonic_child(request.user, request.prefs) for t in song_query ]
    }})
Example #43
0
def new_search():
    query = request.values['query']
    artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
        request.values.get, [
            'artistCount', 'artistOffset', 'albumCount', 'albumOffset',
            'songCount', 'songOffset'
        ])

    artist_count = int(artist_count) if artist_count else 20
    artist_offset = int(artist_offset) if artist_offset else 0
    album_count = int(album_count) if album_count else 20
    album_offset = int(album_offset) if album_offset else 0
    song_count = int(song_count) if song_count else 20
    song_offset = int(song_offset) if song_offset else 0

    artists = select(t.folder.parent for t in Track
                     if query in t.folder.parent.name).limit(
                         artist_count, artist_offset)
    albums = select(t.folder for t in Track
                    if query in t.folder.name).limit(album_count, album_offset)
    songs = Track.select(lambda t: query in t.title).limit(
        song_count, song_offset)

    return request.formatter(
        'searchResult2',
        OrderedDict(
            (('artist', [dict(id=str(a.id), name=a.name) for a in artists]),
             ('album', [f.as_subsonic_child(request.user)
                        for f in albums]), ('song', [
                            t.as_subsonic_child(request.user, request.client)
                            for t in songs
                        ]))))
Example #44
0
def rand_songs():
    size = request.values.get('size', '10')
    genre, fromYear, toYear, musicFolderId = map(
        request.values.get, ['genre', 'fromYear', 'toYear', 'musicFolderId'])

    size = int(size) if size else 10
    fromYear = int(fromYear) if fromYear else None
    toYear = int(toYear) if toYear else None
    fid = uuid.UUID(musicFolderId) if musicFolderId else None

    query = Track.select()
    if fromYear:
        query = query.filter(lambda t: t.year >= fromYear)
    if toYear:
        query = query.filter(lambda t: t.year <= toYear)
    if genre:
        query = query.filter(lambda t: t.genre == genre)
    if fid:
        if not Folder.exists(id=fid, root=True):
            raise NotFound('Folder')

        query = query.filter(lambda t: t.root_folder.id == fid)

    return request.formatter(
        'randomSongs',
        dict(song=[
            t.as_subsonic_child(request.user, request.client)
            for t in query.without_distinct().random(size)
        ]))
Example #45
0
def search_id3():
    query = request.values['query']
    artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
        request.values.get, [
            'artistCount', 'artistOffset', 'albumCount', 'albumOffset',
            'songCount', 'songOffset'
        ])

    artist_count = int(artist_count) if artist_count else 20
    artist_offset = int(artist_offset) if artist_offset else 0
    album_count = int(album_count) if album_count else 20
    album_offset = int(album_offset) if album_offset else 0
    song_count = int(song_count) if song_count else 20
    song_offset = int(song_offset) if song_offset else 0

    artists = Artist.select(lambda a: query in a.name).limit(
        artist_count, artist_offset)
    albums = Album.select(lambda a: query in a.name).limit(
        album_count, album_offset)
    songs = Track.select(lambda t: query in t.title).limit(
        song_count, song_offset)

    return request.formatter(
        'searchResult3',
        OrderedDict(
            (('artist', [a.as_subsonic_artist(request.user) for a in artists]),
             ('album', [a.as_subsonic_album(request.user)
                        for a in albums]), ('song', [
                            t.as_subsonic_child(request.user, request.client)
                            for t in songs
                        ]))))
Example #46
0
def rand_songs():
    size = request.values.get('size', '10')
    genre, fromYear, toYear, musicFolderId = map(request.values.get, [ 'genre', 'fromYear', 'toYear', 'musicFolderId' ])

    size = int(size) if size else 10
    fromYear = int(fromYear) if fromYear else None
    toYear = int(toYear) if toYear else None
    fid = uuid.UUID(musicFolderId) if musicFolderId else None

    query = Track.select()
    if fromYear:
        query = query.filter(lambda t: t.year >= fromYear)
    if toYear:
        query = query.filter(lambda t: t.year <= toYear)
    if genre:
        query = query.filter(lambda t: t.genre == genre)
    if fid:
        if not Folder.exists(id = fid, root = True):
            raise NotFound('Folder')

        query = query.filter(lambda t: t.root_folder.id == fid)

    return request.formatter('randomSongs', dict(
        song = [ t.as_subsonic_child(request.user, request.client) for t in query.without_distinct().random(size) ]
    ))
Example #47
0
def unstar():
    id, albumId, artistId = map(request.args.getlist,
                                ['id', 'albumId', 'artistId'])

    def try_unstar(ent, eid):
        try:
            uid = uuid.UUID(eid)
        except:
            return request.error_formatter(0, 'Invalid id')

        store.find(ent, ent.user_id == request.user.id,
                   ent.starred_id == uid).remove()
        return None

    for eid in id:
        err = try_unstar(StarredTrack, eid)
        if err:
            return err
        err = try_unstar(StarredFolder, eid)
        if err:
            return err

    for alId in albumId:
        err = try_unstar(StarredAlbum, alId)
        if err:
            return err

    for arId in artistId:
        err = try_unstar(StarredArtist, arId)
        if err:
            return err

    store.commit()
    return request.formatter({})
Example #48
0
def list_artists():
    # According to the API page, there are no parameters?
    indexes = dict()
    for artist in Artist.select():
        index = artist.name[0].upper() if artist.name else "?"
        if index in string.digits:
            index = "#"
        elif index not in string.ascii_letters:
            index = "?"

        if index not in indexes:
            indexes[index] = []

        indexes[index].append(artist)

    return request.formatter(
        "artists",
        dict(index=[
            dict(
                name=k,
                artist=[
                    a.as_subsonic_artist(request.user)
                    for a in sorted(v, key=lambda a: a.name.lower())
                ],
            ) for k, v in sorted(indexes.items())
        ]),
    )
Example #49
0
def album_list_id3():
    ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ])
    if not ltype:
        return request.error_formatter(10, 'Missing type')
    try:
        size = int(size) if size else 10
        offset = int(offset) if offset else 0
    except:
        return request.error_formatter(0, 'Invalid parameter format')

    query = store.find(Album)
    if ltype == 'random':
        albums = []
        count = query.count()

        if not count:
            return request.formatter({ 'albumList2': {} })

        for _ in xrange(size):
            x = random.choice(xrange(count))
            albums.append(query[x])

        return request.formatter({
            'albumList2': {
                'album': [ a.as_subsonic_album(request.user) for a in albums ]
            }
        })
    elif ltype == 'newest':
        query = query.find(Track.album_id == Album.id).group_by(Album.id).order_by(Desc(Min(Track.created)))
    elif ltype == 'frequent':
        query = query.find(Track.album_id == Album.id).group_by(Album.id).order_by(Desc(Avg(Track.play_count)))
    elif ltype == 'recent':
        query = query.find(Track.album_id == Album.id).group_by(Album.id).order_by(Desc(Max(Track.last_play)))
    elif ltype == 'starred':
        query = query.find(StarredAlbum.starred_id == Album.id, User.id == StarredAlbum.user_id, User.name == request.username)
    elif ltype == 'alphabeticalByName':
        query = query.order_by(Album.name)
    elif ltype == 'alphabeticalByArtist':
        query = query.find(Artist.id == Album.artist_id).order_by(Artist.name, Album.name)
    else:
        return request.error_formatter(0, 'Unknown search type')

    return request.formatter({
        'albumList2': {
            'album': [ f.as_subsonic_album(request.user) for f in query[offset:offset+size] ]
        }
    })
Example #50
0
def get_album_list_view():
    """Get albums

        params:
           - type   in random,
                    newest,     TODO
                    highest,    TODO
                    frequent,   TODO
                    recent,     TODO
                    starred,    TODO
                    alphabeticalByName, TODO
                    alphabeticalByArtist TODO
           - size   items to return TODO
           - offset paging offset   TODO

        xml response:
            <albumList>
                <album id="11" parent="1" title="Arrival" artist="ABBA" isDir="true" coverArt="22" userRating="4" averageRating="4.5"/>
                <album id="12" parent="1" title="Super Trouper" artist="ABBA" isDir="true" coverArt="23" averageRating="4.4"/>
            </albumList>
    """
    (u, p, v, c, f, callback, dir_id) = map(
        request.args.get, ['u', 'p', 'v', 'c', 'f', 'callback', 'id'])
    (size, type_a, offset) = map(request.args.get, ['size', 'type', 'offset'])

    if not type_a in ['random', 'newest', 'highest', 'frequent', 'recent', 'starred']:
        raise SubsonicProtocolException("Invalid or missing parameter: type")

    try:
        size = int(size)
    except:
        size = 20
    try:
        offset = int(offset)
    except:
        offset = 0

    if type_a == 'random':
        log.info("getting ", type_a)
        albums = app.iposonic.get_albums()
        albums = randomize2_list(albums, size)
    elif type_a == 'highest':
        log.info("getting ", type_a)
        albums = app.iposonic.get_albums(
            query={'userRating': 'notNull'}, order=('userRating', 1))
    elif type_a == 'newest':
        log.info("getting ", type_a)
        albums = app.iposonic.get_albums(
            query={'created': 'notNull'}, order=('created', 1))
    elif type_a == 'starred':
        log.info("getting ", type_a)
        albums = app.iposonic.get_albums(query={'starred': 'notNull'})
    else:
        # get all albums...hey, they may be a lot!
        albums = [a for a in app.iposonic.get_albums()]

    last = min(offset + size, len(albums) - 1)
    log.info("paging albums: %s,%s/%s" % (offset, last, len(albums)))
    return request.formatter({'albumList': {'album': albums[offset:last]}})
Example #51
0
def artist_info():
    res = get_entity(Artist)
    info = res.as_subsonic_artist(request.user)
    albums  = set(res.albums)
    albums |= { t.album for t in res.tracks }
    info['album'] = [ a.as_subsonic_album(request.user) for a in sorted(albums, key = lambda a: a.sort_key()) ]

    return request.formatter('artist', info)
Example #52
0
def get_starred_id3():
	return request.formatter({
		'starred2': {
			'artist': [ sa.starred.as_subsonic_artist(request.user) for sa in StarredArtist.query.join(User).filter(User.name == request.username) ],
			'album': [ sa.starred.as_subsonic_album(request.user) for sa in StarredAlbum.query.join(User).filter(User.name == request.username) ],
			'song': [ st.starred.as_subsonic_child(request.user) for st in StarredTrack.query.join(User).filter(User.name == request.username) ]
		}
	})
Example #53
0
def get_starred():
	return request.formatter({
		'starred': {
			'artist': [ { 'id': str(sf.starred_id), 'name': sf.starred.name } for sf in StarredFolder.query.join(User).join(Folder).filter(User.name == request.username).filter(~ Folder.tracks.any()) ],
			'album': [ sf.starred.as_subsonic_child(request.user) for sf in StarredFolder.query.join(User).join(Folder).filter(User.name == request.username).filter(Folder.tracks.any()) ],
			'song': [ st.starred.as_subsonic_child(request.user) for st in StarredTrack.query.join(User).filter(User.name == request.username) ]
		}
	})
Example #54
0
def show_playlist():
	status, res = get_entity(request, Playlist)
	if not status:
		return res

	info = res.as_subsonic_playlist(request.user)
	info['entry'] = [ t.as_subsonic_child(request.user) for t in res.tracks ]
	return request.formatter({ 'playlist': info })
Example #55
0
def get_starred():
    folders = select(s.starred for s in StarredFolder if s.user.id == request.user.id)

    return request.formatter('starred', dict(
        artist = [ dict(id = str(sf.id), name = sf.name) for sf in folders.filter(lambda f: count(f.tracks) == 0) ],
        album = [ sf.as_subsonic_child(request.user) for sf in folders.filter(lambda f: count(f.tracks) > 0) ],
        song = [ st.as_subsonic_child(request.user, request.client) for st in select(s.starred for s in StarredTrack if s.user.id == request.user.id) ]
    ))
Example #56
0
def get_starred_id3():
	return request.formatter({
		'starred2': {
			'artist': [ sa.starred.as_subsonic_artist(request.user) for sa in store.find(StarredArtist, StarredArtist.user_id == User.id, User.name == request.username) ],
			'album': [ sa.starred.as_subsonic_album(request.user) for sa in store.find(StarredAlbum, StarredAlbum.user_id == User.id, User.name == request.username) ],
			'song': [ st.starred.as_subsonic_child(request.user) for st in store.find(StarredTrack, StarredTrack.user_id == User.id, User.name == request.username) ]
		}
	})
Example #57
0
def add_chat_message():
    msg = request.args.get("message")
    if not msg:
        return request.error_formatter(10, "Missing message")

    session.add(ChatMessage(user=request.user, message=msg))
    session.commit()
    return request.formatter({})