def cover_art(): status, res = get_entity(request, Folder) if not status: return res if not res.has_cover_art or not os.path.isfile(os.path.join(res.path, 'cover.jpg')): return request.error_formatter(70, 'Cover art not found') size = request.args.get('size') if size: try: size = int(size) except: return request.error_formatter(0, 'Invalid size value') else: return send_file(os.path.join(res.path, 'cover.jpg')) im = Image.open(os.path.join(res.path, 'cover.jpg')) if size > im.size[0] and size > im.size[1]: return send_file(os.path.join(res.path, 'cover.jpg')) size_path = os.path.join(config.get('base', 'cache_dir'), str(size)) path = os.path.join(size_path, str(res.id)) if os.path.exists(path): return send_file(path) if not os.path.exists(size_path): os.makedirs(size_path) im.thumbnail([size, size], Image.ANTIALIAS) im.save(path, 'JPEG') return send_file(path)
def album_info(): status, res = get_entity(request, Album) if not status: return res info = res.as_subsonic_album(request.user) info['song'] = [ t.as_subsonic_child(request.user) for t in sorted(res.tracks, key = lambda t: t.sort_key()) ] return request.formatter({ 'album': info })
def artist_info(): status, res = get_entity(request, Artist) if not status: return res info = res.as_subsonic_artist(request.user) info['album'] = [ a.as_subsonic_album(request.user) for a in sorted(res.albums, key = lambda a: a.sort_key()) ] return request.formatter({ 'artist': info })
def show_directory(): status, res = get_entity(request, Folder) if not status: return res directory = { 'id': str(res.id), 'name': res.name, 'child': [ f.as_subsonic_child(request.user) for f in sorted(res.children, key = lambda c: c.name.lower()) ] + [ t.as_subsonic_child(request.user) for t in sorted(res.tracks, key = lambda t: t.sort_key()) ] } if not res.root: directory['parent'] = str(res.parent_id) return request.formatter({ 'directory': directory })
def scrobble(): status, res = get_entity(request, Track) if not status: return res t, submission = map(request.args.get, [ 'time', 'submission' ]) if t: try: t = int(t) / 1000 except: return request.error_formatter(0, 'Invalid time value') else: t = int(time.time()) lfm = LastFm(request.user, app.logger) if submission in (None, '', True, 'true', 'True', 1, '1'): lfm.scrobble(res, t) else: lfm.now_playing(res) return request.formatter({})
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 = ClientPrefs.query.get((request.user.id, client)) if not prefs: prefs = ClientPrefs(user_id = request.user.id, client_name = client) session.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() session.commit() return response
def download_media(): status, res = get_entity(request, Track) if not status: return res return send_file(res.path)
def stream_media(): status, res = get_entity(request, Track) if not status: return res maxBitRate, format, timeOffset, size, estimateContentLength = map(request.args.get, [ 'maxBitRate', 'format', 'timeOffset', 'size', 'estimateContentLength' ]) if format: format = format.lower() do_transcoding = False src_suffix = res.suffix() dst_suffix = res.suffix() dst_bitrate = res.bitrate dst_mimetype = res.content_type if format != 'raw': # That's from API 1.9.0 but whatever if maxBitRate: try: maxBitRate = int(maxBitRate) except: return request.error_formatter(0, 'Invalid bitrate value') if dst_bitrate > maxBitRate and maxBitRate != 0: do_transcoding = True dst_bitrate = maxBitRate if format and format != src_suffix: do_transcoding = True dst_suffix = format dst_mimetype = scanner.get_mime(dst_suffix) if do_transcoding: 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 ]) 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) def transcode(): while True: data = proc.stdout.read(8192) if not data: break yield data proc.terminate() proc.wait() response = Response(transcode(), mimetype = dst_mimetype) else: response = send_file(res.path, mimetype = dst_mimetype) # TODO handle estimateContentLength res.play_count = res.play_count + 1 res.last_play = now() request.user.last_play = res request.user.last_play_date = now() session.commit() return response
def track_info(): status, res = get_entity(request, Track) if not status: return res return request.formatter({ 'song': res.as_subsonic_child(request.user) })