Пример #1
0
def try_star(ent, starred_ent, eid):
    """ Stars an entity

    :param ent: entity class, Folder, Artist, Album or Track
    :param starred_ent: class used for the db representation of the starring of ent
    :param eid: id of the entity to star
    :return error dict, if any. None otherwise
    """

    try:
        uid = uuid.UUID(eid)
    except:
        return { 'code': 0, 'message': 'Invalid {} id {}'.format(ent.__name__, eid) }

    if store.get(starred_ent, (request.user.id, uid)):
        return { 'code': 0, 'message': '{} {} already starred'.format(ent.__name__, eid) }

    e = store.get(ent, uid)
    if not e:
        return { 'code': 70, 'message': 'Unknown {} id {}'.format(ent.__name__, eid) }

    starred = starred_ent()
    starred.user_id = request.user.id
    starred.starred_id = uid
    store.add(starred)

    return None
Пример #2
0
def update_clients(uid, user):
    clients_opts = {}
    for key, value in request.form.iteritems():
        if '_' not in key:
            continue
        parts = key.split('_')
        if len(parts) != 2:
            continue
        client, opt = parts
        if not client or not opt:
            continue

        if client not in clients_opts:
            clients_opts[client] = { opt: value }
        else:
            clients_opts[client][opt] = value
    app.logger.debug(clients_opts)

    for client, opts in clients_opts.iteritems():
        prefs = store.get(ClientPrefs, (user.id, client))
        if not prefs:
            continue

        if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]:
            store.remove(prefs)
            continue

        prefs.format  =     opts['format']   if 'format'  in opts and opts['format']  else None
        prefs.bitrate = int(opts['bitrate']) if 'bitrate' in opts and opts['bitrate'] else None

    store.commit()
    flash('Clients preferences updated.')
    return user_profile(uid, user)
Пример #3
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({})
Пример #4
0
def update_clients(uid):
	clients_opts = {}
	for client in set(map(lambda k: k.rsplit('_', 1)[0], request.form.keys())):
		clients_opts[client] = { k.rsplit('_', 1)[1]: v for k, v in filter(lambda (k, v): k.startswith(client), request.form.iteritems()) }
	app.logger.debug(clients_opts)

	if uid == 'me':
		userid = uuid.UUID(session.get('userid'))
	else:
		if not UserManager.get(store, session.get('userid'))[1].admin or not UserManager.get(store, uid)[0] is UserManager.SUCCESS:
			return redirect(url_for('index'))
		userid = uuid.UUID(uid)

	for client, opts in clients_opts.iteritems():
		prefs = store.get(ClientPrefs, (userid, client))
		if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]:
			store.remove(prefs)
			continue

		prefs.format  =     opts['format']   if 'format'  in opts and opts['format']  else None
		prefs.bitrate = int(opts['bitrate']) if 'bitrate' in opts and opts['bitrate'] else None

	store.commit()
	flash('Clients preferences updated.')
	return user_profile(uid)
Пример #5
0
def update_clients(uid, user):
    clients_opts = {}
    for key, value in request.form.iteritems():
        if '_' not in key:
            continue
        parts = key.split('_')
        if len(parts) != 2:
            continue
        client, opt = parts
        if not client or not opt:
            continue

        if client not in clients_opts:
            clients_opts[client] = { opt: value }
        else:
            clients_opts[client][opt] = value
    app.logger.debug(clients_opts)

    for client, opts in clients_opts.iteritems():
        prefs = store.get(ClientPrefs, (user.id, client))
        if not prefs:
            continue

        if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]:
            store.remove(prefs)
            continue

        prefs.format  =     opts['format']   if 'format'  in opts and opts['format']  else None
        prefs.bitrate = int(opts['bitrate']) if 'bitrate' in opts and opts['bitrate'] else None

    store.commit()
    flash('Clients preferences updated.')
    return user_profile(uid, user)
Пример #6
0
	def try_star(ent, starred_ent, eid):
		try:
			uid = uuid.UUID(eid)
		except:
			return 2, request.error_formatter(0, 'Invalid %s id' % ent.__name__)

		if store.get(starred_ent, (request.user.id, uid)):
			return 2, request.error_formatter(0, '%s already starred' % ent.__name__)
		e = store.get(ent, uid)
		if e:
			starred = starred_ent()
			starred.user_id = request.user.id
			starred.starred_id = uid
			store.add(starred)
		else:
			return 1, request.error_formatter(70, 'Unknown %s id' % ent.__name__)

		return 0, None
Пример #7
0
def create_playlist():
    # Only(?) method where the android client uses form data rather than GET params
    playlist_id, name = map(
        lambda x: request.args.get(x) or request.form.get(x),
        ['playlistId', 'name'])
    # songId actually doesn't seem to be required
    songs = request.args.getlist('songId') or request.form.getlist('songId')
    try:
        playlist_id = uuid.UUID(playlist_id) if playlist_id else None
        songs = set(map(uuid.UUID, songs))
    except:
        return request.error_formatter(0, 'Invalid parameter')

    if playlist_id:
        playlist = store.get(Playlist, playlist_id)
        if not playlist:
            return request.error_formatter(70, 'Unknwon playlist')

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

        playlist.tracks.clear()
        if name:
            playlist.name = name
    elif name:
        playlist = Playlist()
        playlist.user_id = request.user.id
        playlist.name = name
        store.add(playlist)
    else:
        return request.error_formatter(10, 'Missing playlist id or name')

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

        playlist.tracks.add(track)

    store.commit()
    return request.formatter({})
Пример #8
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:
        store.find(RatingTrack, RatingTrack.user_id == request.user.id,
                   RatingTrack.rated_id == uid).remove()
        store.find(RatingFolder, RatingFolder.user_id == request.user.id,
                   RatingFolder.rated_id == uid).remove()
    else:
        rated = store.get(Track, uid)
        rating_ent = RatingTrack
        if not rated:
            rated = store.get(Folder, uid)
            rating_ent = RatingFolder
            if not rated:
                return request.error_formatter(70, 'Unknown id')

        rating_info = store.get(rating_ent, (request.user.id, uid))
        if rating_info:
            rating_info.rating = rating
        else:
            rating_info = rating_ent()
            rating_info.user_id = request.user.id
            rating_info.rated_id = uid
            rating_info.rating = rating
            store.add(rating_info)

    store.commit()
    return request.formatter({})
Пример #9
0
    def try_star(ent, starred_ent, eid):
        try:
            uid = uuid.UUID(eid)
        except:
            return 2, request.error_formatter(0,
                                              'Invalid %s id' % ent.__name__)

        if store.get(starred_ent, (request.user.id, uid)):
            return 2, request.error_formatter(
                0, '%s already starred' % ent.__name__)
        e = store.get(ent, uid)
        if e:
            starred = starred_ent()
            starred.user_id = request.user.id
            starred.starred_id = uid
            store.add(starred)
        else:
            return 1, request.error_formatter(70,
                                              'Unknown %s id' % ent.__name__)

        return 0, None
Пример #10
0
def create_playlist():
    # Only(?) method where the android client uses form data rather than GET params
    playlist_id, name = map(request.values.get, [ 'playlistId', 'name' ])
    # songId actually doesn't seem to be required
    songs = request.values.getlist('songId')
    try:
        playlist_id = uuid.UUID(playlist_id) if playlist_id else None
        songs = map(uuid.UUID, songs)
    except:
        return request.error_formatter(0, 'Invalid parameter')

    if playlist_id:
        playlist = store.get(Playlist, playlist_id)
        if not playlist:
            return request.error_formatter(70, 'Unknwon playlist')

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

        playlist.clear()
        if name:
            playlist.name = name
    elif name:
        playlist = Playlist()
        playlist.user_id = request.user.id
        playlist.name = name
        store.add(playlist)
    else:
        return request.error_formatter(10, 'Missing playlist id or name')

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

        playlist.add(track)

    store.commit()
    return request.formatter({})
Пример #11
0
def playlist_details(uid):
	try:
		uid = uuid.UUID(uid) if type(uid) in (str, unicode) else uid
	except:
		flash('Invalid playlist id')
		return redirect(url_for('playlist_index'))

	playlist = store.get(Playlist, uid)
	if not playlist:
		flash('Unknown playlist')
		return redirect(url_for('playlist_index'))

	return render_template('playlist.html', playlist = playlist)
Пример #12
0
def rate():
	id, rating = map(request.values.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:
		store.find(RatingTrack, RatingTrack.user_id == request.user.id, RatingTrack.rated_id == uid).remove()
		store.find(RatingFolder, RatingFolder.user_id == request.user.id, RatingFolder.rated_id == uid).remove()
	else:
		rated = store.get(Track, uid)
		rating_ent = RatingTrack
		if not rated:
			rated = store.get(Folder, uid)
			rating_ent = RatingFolder
			if not rated:
				return request.error_formatter(70, 'Unknown id')

		rating_info = store.get(rating_ent, (request.user.id, uid))
		if rating_info:
			rating_info.rating = rating
		else:
			rating_info = rating_ent()
			rating_info.user_id = request.user.id
			rating_info.rated_id = uid
			rating_info.rating = rating
			store.add(rating_info)

	store.commit()
	return request.formatter({})
Пример #13
0
def get_client_prefs():
	if not request.path.startswith('/rest/'):
		return

	client = request.values.get('c')
	prefs = store.get(ClientPrefs, (request.user.id, client))
	if not prefs:
		prefs = ClientPrefs()
		prefs.user_id = request.user.id
		prefs.client_name = client
		store.add(prefs)
		store.commit()

	request.prefs = prefs
Пример #14
0
def get_entity(req, ent, param = 'id'):
    eid = req.values.get(param)
    if not eid:
        return False, req.error_formatter(10, 'Missing %s id' % ent.__name__)

    try:
        eid = uuid.UUID(eid)
    except:
        return False, req.error_formatter(0, 'Invalid %s id' % ent.__name__)

    entity = store.get(ent, eid)
    if not entity:
        return False, (req.error_formatter(70, '%s not found' % ent.__name__), 404)

    return True, entity
Пример #15
0
def try_star(ent, starred_ent, eid):
    """ Stars an entity

    :param ent: entity class, Folder, Artist, Album or Track
    :param starred_ent: class used for the db representation of the starring of ent
    :param eid: id of the entity to star
    :return error dict, if any. None otherwise
    """

    try:
        uid = uuid.UUID(eid)
    except:
        return {
            'code': 0,
            'message': 'Invalid {} id {}'.format(ent.__name__, eid)
        }

    if store.get(starred_ent, (request.user.id, uid)):
        return {
            'code': 0,
            'message': '{} {} already starred'.format(ent.__name__, eid)
        }

    e = store.get(ent, uid)
    if not e:
        return {
            'code': 70,
            'message': 'Unknown {} id {}'.format(ent.__name__, eid)
        }

    starred = starred_ent()
    starred.user_id = request.user.id
    starred.starred_id = uid
    store.add(starred)

    return None
Пример #16
0
def get_entity(req, ent, param = 'id'):
	eid = req.args.get(param)
	if not eid:
		return False, req.error_formatter(10, 'Missing %s id' % ent.__name__)

	try:
		eid = uuid.UUID(eid)
	except:
		return False, req.error_formatter(0, 'Invalid %s id' % ent.__name__)

	entity = store.get(ent, eid)
	if not entity:
		return False, (req.error_formatter(70, '%s not found' % ent.__name__), 404)

	return True, entity
Пример #17
0
def get_client_prefs():
    if not request.path.startswith('/rest/'):
        return

    if 'c' not in request.values:
        return request.error_formatter(10, 'Missing required parameter')

    client = request.values.get('c')
    prefs = store.get(ClientPrefs, (request.user.id, client))
    if not prefs:
        prefs = ClientPrefs()
        prefs.user_id = request.user.id
        prefs.client_name = client
        store.add(prefs)
        store.commit()

    request.prefs = prefs
Пример #18
0
def get_client_prefs():
    if not request.path.startswith('/rest/'):
        return

    if 'c' not in request.values:
        return request.error_formatter(10, 'Missing required parameter')

    client = request.values.get('c')
    prefs = store.get(ClientPrefs, (request.user.id, client))
    if not prefs:
        prefs = ClientPrefs()
        prefs.user_id = request.user.id
        prefs.client_name = client
        store.add(prefs)
        store.commit()

    request.prefs = prefs
Пример #19
0
def update_clients():
	clients_opts = {}
	for client in set(map(lambda k: k.rsplit('_', 1)[0], request.form.keys())):
		clients_opts[client] = { k.rsplit('_', 1)[1]: v for k, v in filter(lambda (k, v): k.startswith(client), request.form.iteritems()) }
	app.logger.debug(clients_opts)

	for client, opts in clients_opts.iteritems():
		prefs = store.get(ClientPrefs, (uuid.UUID(session.get('userid')), client))
		if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]:
			store.remove(prefs)
			continue

		prefs.format  =     opts['format']   if 'format'  in opts and opts['format']  else None
		prefs.bitrate = int(opts['bitrate']) if 'bitrate' in opts and opts['bitrate'] else None

	store.commit()
	flash('Clients preferences updated.')
	return user_profile()
Пример #20
0
def playlist_delete(uid):
	try:
		uid = uuid.UUID(uid)
	except:
		flash('Invalid playlist id')
		return redirect(url_for('playlist_index'))

	playlist = store.get(Playlist, uid)
	if not playlist:
		flash('Unknown playlist')
	elif str(playlist.user_id) != session.get('userid'):
		flash("You're not allowed to delete this playlist")
	else:
		store.remove(playlist)
		store.commit()
		flash('Playlist deleted')

	return redirect(url_for('playlist_index'))
Пример #21
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.args.get,
                                ['name', 'comment', 'public'])
    to_add, to_remove = map(request.args.getlist,
                            ['songIdToAdd', 'songIndexToRemove'])
    try:
        to_add = set(map(uuid.UUID, to_add))
        to_remove = sorted(set(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')

    tracks = list(playlist.tracks)

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

    for idx in to_remove:
        if idx < 0 or idx >= len(tracks):
            return request.error_formatter(0, 'Index out of range')
        playlist.tracks.remove(tracks[idx])

    store.commit()
    return request.formatter({})
Пример #22
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 = set(map(uuid.UUID, to_add))
        to_remove = sorted(set(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")

    tracks = list(playlist.tracks)

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

    for idx in to_remove:
        if idx < 0 or idx >= len(tracks):
            return request.error_formatter(0, "Index out of range")
        playlist.tracks.remove(tracks[idx])

    store.commit()
    return request.formatter({})
Пример #23
0
def playlist_update(uid):
	try:
		uid = uuid.UUID(uid)
	except:
		flash('Invalid playlist id')
		return redirect(url_for('playlist_index'))

	playlist = store.get(Playlist, uid)
	if not playlist:
		flash('Unknown playlist')
		return redirect(url_for('playlist_index'))

	if str(playlist.user_id) != session.get('userid'):
		flash("You're not allowed to edit this playlist")
	elif not request.form.get('name'):
		flash('Missing playlist name')
	else:
		playlist.name = request.form.get('name')
		playlist.public = request.form.get('public') in (True, 'True', 1, '1', 'on', 'checked')
		store.commit()
		flash('Playlist updated.')

	return playlist_details(uid)
Пример #24
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({})
Пример #25
0
def list_indexes():
    musicFolderId = request.args.get('musicFolderId')
    ifModifiedSince = request.args.get('ifModifiedSince')
    if ifModifiedSince:
        try:
            ifModifiedSince = int(ifModifiedSince) / 1000
        except:
            return request.error_formatter(0, 'Invalid timestamp')

    if musicFolderId is None:
        folder = store.find(Folder, Folder.root == True)
    else:
        try:
            mfid = uuid.UUID(musicFolderId)
        except:
            return request.error_formatter(0, 'Invalid id')

        folder = store.get(Folder, mfid)

    if not folder or (type(folder) is Folder and not folder.root):
        return request.error_formatter(70, 'Folder not found')

    last_modif = max(
        map(lambda f: f.last_scan,
            folder)) if type(folder) is not Folder else folder.last_scan

    if (not ifModifiedSince is None) and last_modif < ifModifiedSince:
        return request.formatter(
            {'indexes': {
                'lastModified': last_modif * 1000
            }})

    # The XSD lies, we don't return artists but a directory structure
    if type(folder) is not Folder:
        artists = []
        childs = []
        for f in folder:
            artists += f.children
            childs += f.tracks
    else:
        artists = folder.children
        childs = folder.tracks

    indexes = {}
    for artist in artists:
        index = artist.name[0].upper()
        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({
        'indexes': {
            'lastModified':
            last_modif * 1000,
            'index': [{
                'name':
                k,
                'artist': [{
                    'id': str(a.id),
                    'name': a.name
                } for a in sorted(v, key=lambda a: a.name.lower())]
            } for k, v in sorted(indexes.iteritems())],
            'child': [
                c.as_subsonic_child(request.user)
                for c in sorted(childs, key=lambda t: t.sort_key())
            ]
        }
    })
Пример #26
0
def stream_media():
	status, res = get_entity(request, Track)
	if not status:
		return res

	maxBitRate, format, timeOffset, size, estimateContentLength, client = map(request.args.get, [ 'maxBitRate', 'format', 'timeOffset', 'size', 'estimateContentLength', 'c' ])
	if format:
		format = format.lower()

	src_suffix = res.suffix()
	dst_suffix = res.suffix()
	dst_bitrate = res.bitrate
	dst_mimetype = res.content_type

	if client:
		prefs = store.get(ClientPrefs, (request.user.id, client))
		if not prefs:
			prefs = ClientPrefs()
			prefs.user_id = request.user.id
			prefs.client_name = client
			store.add(prefs)

		if prefs.format:
			dst_suffix = prefs.format
		if prefs.bitrate and prefs.bitrate < dst_bitrate:
			dst_bitrate = prefs.bitrate

	if maxBitRate:
		try:
			maxBitRate = int(maxBitRate)
		except:
			return request.error_formatter(0, 'Invalid bitrate value')

		if dst_bitrate > maxBitRate and maxBitRate != 0:
			dst_bitrate = maxBitRate

	if format and format != 'raw' and format != src_suffix:
		dst_suffix = format
		dst_mimetype = scanner.get_mime(dst_suffix)

	if format != 'raw' and (dst_suffix != src_suffix or dst_bitrate != res.bitrate):
		transcoder = config.get('transcoding', 'transcoder_{}_{}'.format(src_suffix, dst_suffix))
		decoder = config.get('transcoding', 'decoder_' + src_suffix) or config.get('transcoding', 'decoder')
		encoder = config.get('transcoding', 'encoder_' + dst_suffix) or config.get('transcoding', 'encoder')
		if not transcoder and (not decoder or not encoder):
			transcoder = config.get('transcoding', 'transcoder')
			if not transcoder:
				return request.error_formatter(0, 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix))

		transcoder, decoder, encoder = map(lambda x: prepare_transcoding_cmdline(x, res.path, src_suffix, dst_suffix, dst_bitrate), [ transcoder, decoder, encoder ])
		try:
			if transcoder:
				proc = subprocess.Popen(transcoder, stdout = subprocess.PIPE)
			else:
				dec_proc = subprocess.Popen(decoder, stdout = subprocess.PIPE)
				proc = subprocess.Popen(encoder, stdin = dec_proc.stdout, stdout = subprocess.PIPE)
		except:
			return request.error_formatter(0, 'Error while running the transcoding process')

		def transcode():
			while True:
				data = proc.stdout.read(8192)
				if not data:
					break
				yield data
			proc.terminate()
			proc.wait()

		app.logger.info('Transcoding track {0.id} for user {1.id}. Source: {2} at {0.bitrate}kbps. Dest: {3} at {4}kbps'.format(res, request.user, src_suffix, dst_suffix, dst_bitrate))
		response = Response(transcode(), mimetype = dst_mimetype)
	else:
		response = send_file(res.path, mimetype = dst_mimetype)

	res.play_count = res.play_count + 1
	res.last_play = now()
	request.user.last_play = res
	request.user.last_play_date = now()
	store.commit()

	return response
Пример #27
0
def list_indexes():
	musicFolderId = request.values.get('musicFolderId')
	ifModifiedSince = request.values.get('ifModifiedSince')
	if ifModifiedSince:
		try:
			ifModifiedSince = int(ifModifiedSince) / 1000
		except:
			return request.error_formatter(0, 'Invalid timestamp')

	if musicFolderId is None:
		folder = store.find(Folder, Folder.root == True)
	else:
		try:
			mfid = uuid.UUID(musicFolderId)
		except:
			return request.error_formatter(0, 'Invalid id')

		folder = store.get(Folder, mfid)

	if not folder or (type(folder) is Folder and not folder.root):
		return request.error_formatter(70, 'Folder not found')

	last_modif = max(map(lambda f: f.last_scan, folder)) if type(folder) is not Folder else folder.last_scan

	if (not ifModifiedSince is None) and last_modif < ifModifiedSince:
		return request.formatter({ 'indexes': { 'lastModified': last_modif * 1000 } })

	# The XSD lies, we don't return artists but a directory structure
	if type(folder) is not Folder:
		artists = []
		childs = []
		for f in folder:
			artists += f.children
			childs += f.tracks
	else:
		artists = folder.children
		childs = folder.tracks

	indexes = {}
	for artist in artists:
		index = artist.name[0].upper()
		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({
		'indexes': {
			'lastModified': last_modif * 1000,
			'index': [ {
				'name': k,
				'artist': [ {
					'id': str(a.id),
					'name': a.name
				} for a in sorted(v, key = lambda a: a.name.lower()) ]
			} for k, v in sorted(indexes.iteritems()) ],
			'child': [ c.as_subsonic_child(request.user, request.prefs) for c in sorted(childs, key = lambda t: t.sort_key()) ]
		}
	})
Пример #28
0
def stream_media():
	status, res = get_entity(request, Track)
	if not status:
		return res

	maxBitRate, format, timeOffset, size, estimateContentLength, client = map(request.values.get, [ 'maxBitRate', 'format', 'timeOffset', 'size', 'estimateContentLength', 'c' ])
	if format:
		format = format.lower()

	src_suffix = res.suffix()
	dst_suffix = res.suffix()
	dst_bitrate = res.bitrate
	dst_mimetype = res.content_type

	if client:
		prefs = store.get(ClientPrefs, (request.user.id, client))
		if not prefs:
			prefs = ClientPrefs()
			prefs.user_id = request.user.id
			prefs.client_name = client
			store.add(prefs)

		if prefs.format:
			dst_suffix = prefs.format
		if prefs.bitrate and prefs.bitrate < dst_bitrate:
			dst_bitrate = prefs.bitrate

	if maxBitRate:
		try:
			maxBitRate = int(maxBitRate)
		except:
			return request.error_formatter(0, 'Invalid bitrate value')

		if dst_bitrate > maxBitRate and maxBitRate != 0:
			dst_bitrate = maxBitRate

	if format and format != 'raw' and format != src_suffix:
		dst_suffix = format
		dst_mimetype = scanner.get_mime(dst_suffix)

	if format != 'raw' and (dst_suffix != src_suffix or dst_bitrate != res.bitrate):
		transcoder = config.get('transcoding', 'transcoder_{}_{}'.format(src_suffix, dst_suffix))
		decoder = config.get('transcoding', 'decoder_' + src_suffix) or config.get('transcoding', 'decoder')
		encoder = config.get('transcoding', 'encoder_' + dst_suffix) or config.get('transcoding', 'encoder')
		if not transcoder and (not decoder or not encoder):
			transcoder = config.get('transcoding', 'transcoder')
			if not transcoder:
				return request.error_formatter(0, 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix))

		transcoder, decoder, encoder = map(lambda x: prepare_transcoding_cmdline(x, res.path, src_suffix, dst_suffix, dst_bitrate), [ transcoder, decoder, encoder ])
		try:
			if transcoder:
				dec_proc = None
				proc = subprocess.Popen(transcoder, stdout = subprocess.PIPE)
			else:
				dec_proc = subprocess.Popen(decoder, stdout = subprocess.PIPE)
				proc = subprocess.Popen(encoder, stdin = dec_proc.stdout, stdout = subprocess.PIPE)
		except:
			return request.error_formatter(0, 'Error while running the transcoding process')

		def transcode():
			try:
				while True:
					data = proc.stdout.read(8192)
					if not data:
						break
					yield data
			except:
				if dec_proc != None:
					dec_proc.terminate()
				proc.terminate()

			if dec_proc != None:
				dec_proc.wait()
			proc.wait()

		app.logger.info('Transcoding track {0.id} for user {1.id}. Source: {2} at {0.bitrate}kbps. Dest: {3} at {4}kbps'.format(res, request.user, src_suffix, dst_suffix, dst_bitrate))
		response = Response(transcode(), mimetype = dst_mimetype)
	else:
		response = send_file(res.path, mimetype = dst_mimetype)

	res.play_count = res.play_count + 1
	res.last_play = now()
	request.user.last_play = res
	request.user.last_play_date = now()
	store.commit()

	return response