2012-10-20 18:05:39 +00:00
# coding: utf-8
2013-10-15 11:14:20 +00:00
from flask import request , send_file , Response
2012-12-02 15:42:25 +00:00
import os . path
2013-06-07 13:31:30 +00:00
from PIL import Image
2013-10-15 11:14:20 +00:00
import subprocess
2012-11-23 16:13:25 +00:00
2013-10-15 11:14:20 +00:00
import config , scanner
2012-11-23 16:13:25 +00:00
from web import app
2013-12-07 17:46:30 +00:00
from db import Track , Folder , User , ClientPrefs , now , session
2012-12-02 15:42:25 +00:00
from api import get_entity
2012-10-20 18:05:39 +00:00
2013-10-15 11:14:20 +00:00
def prepare_transcoding_cmdline ( base_cmdline , input_file , input_format , output_format , output_bitrate ) :
if not base_cmdline :
return None
ret = base_cmdline . split ( )
for i in xrange ( len ( ret ) ) :
ret [ i ] = ret [ i ] . replace ( ' %s rcpath ' , input_file ) . replace ( ' %s rcfmt ' , input_format ) . replace ( ' %o utfmt ' , output_format ) . replace ( ' %o utrate ' , str ( output_bitrate ) )
return ret
2012-11-22 13:51:43 +00:00
@app.route ( ' /rest/stream.view ' , methods = [ ' GET ' , ' POST ' ] )
2012-10-20 18:05:39 +00:00
def stream_media ( ) :
2012-12-02 15:42:25 +00:00
status , res = get_entity ( request , Track )
if not status :
return res
2012-10-20 18:05:39 +00:00
2013-12-07 17:46:30 +00:00
maxBitRate , format , timeOffset , size , estimateContentLength , client = map ( request . args . get , [ ' maxBitRate ' , ' format ' , ' timeOffset ' , ' size ' , ' estimateContentLength ' , ' c ' ] )
2013-10-15 08:32:35 +00:00
if format :
format = format . lower ( )
2012-10-20 18:05:39 +00:00
2013-10-15 11:14:20 +00:00
src_suffix = res . suffix ( )
dst_suffix = res . suffix ( )
dst_bitrate = res . bitrate
dst_mimetype = res . content_type
2013-12-07 17:46:30 +00:00
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 )
2012-10-20 18:05:39 +00:00
2013-12-07 17:46:30 +00:00
if prefs . format :
dst_suffix = prefs . format
if prefs . bitrate and prefs . bitrate < dst_bitrate :
dst_bitrate = prefs . bitrate
2013-10-15 11:14:20 +00:00
2013-12-07 17:46:30 +00:00
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 )
2013-10-15 11:14:20 +00:00
2013-12-07 17:46:30 +00:00
if format != ' raw ' and ( dst_suffix != src_suffix or dst_bitrate != res . bitrate ) :
2013-10-15 11:14:20 +00:00
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 ) )
2013-10-14 16:36:45 +00:00
2013-10-15 11:14:20 +00:00
transcoder , decoder , encoder = map ( lambda x : prepare_transcoding_cmdline ( x , res . path , src_suffix , dst_suffix , dst_bitrate ) , [ transcoder , decoder , encoder ] )
2013-10-20 15:27:20 +00:00
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 ' )
2013-10-15 11:14:20 +00:00
def transcode ( ) :
while True :
data = proc . stdout . read ( 8192 )
if not data :
break
yield data
proc . terminate ( )
proc . wait ( )
2013-12-07 17:46:30 +00:00
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 ) )
2013-10-15 11:14:20 +00:00
response = Response ( transcode ( ) , mimetype = dst_mimetype )
else :
2013-10-15 16:26:41 +00:00
response = send_file ( res . path , mimetype = dst_mimetype )
2013-10-15 11:14:20 +00:00
2013-06-07 18:35:21 +00:00
res . play_count = res . play_count + 1
res . last_play = now ( )
2013-06-13 16:17:33 +00:00
request . user . last_play = res
request . user . last_play_date = now ( )
2013-06-07 18:35:21 +00:00
session . commit ( )
2013-10-15 11:14:20 +00:00
return response
2012-10-20 18:05:39 +00:00
2013-06-12 19:29:42 +00:00
@app.route ( ' /rest/download.view ' , methods = [ ' GET ' , ' POST ' ] )
def download_media ( ) :
status , res = get_entity ( request , Track )
if not status :
return res
return send_file ( res . path )
2012-11-22 13:51:43 +00:00
@app.route ( ' /rest/getCoverArt.view ' , methods = [ ' GET ' , ' POST ' ] )
2012-11-11 20:39:26 +00:00
def cover_art ( ) :
2012-12-02 15:42:25 +00:00
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 ' ) ) :
2012-11-11 20:39:26 +00:00
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 :
2012-12-02 15:42:25 +00:00
return send_file ( os . path . join ( res . path , ' cover.jpg ' ) )
2012-11-11 20:39:26 +00:00
2012-12-02 15:42:25 +00:00
im = Image . open ( os . path . join ( res . path , ' cover.jpg ' ) )
2012-11-11 20:39:26 +00:00
if size > im . size [ 0 ] and size > im . size [ 1 ] :
2012-12-02 15:42:25 +00:00
return send_file ( os . path . join ( res . path , ' cover.jpg ' ) )
2012-11-11 20:39:26 +00:00
2013-07-15 12:37:51 +00:00
size_path = os . path . join ( config . get ( ' base ' , ' cache_dir ' ) , str ( size ) )
2012-12-02 15:42:25 +00:00
path = os . path . join ( size_path , str ( res . id ) )
2012-11-11 20:39:26 +00:00
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 )