Add FLAC support

This commit is contained in:
An Phan 2016-01-28 23:19:06 +08:00
parent 20157e489e
commit 65fb45f08a
5 changed files with 168 additions and 48 deletions

View file

@ -13,6 +13,7 @@ APP_KEY=
# Another random 32-char string
JWT_SECRET=
# Username and password for the initial admin account
# This info will be populated into the database during `php artisan db:seed`
# After that, it can (and should) be removed from this .env file
@ -20,12 +21,15 @@ ADMIN_EMAIL=
ADMIN_NAME=
ADMIN_PASSWORD=
# The maximum scan time, in seconds. Increase this if you have a huge library.
APP_MAX_SCAN_TIME=600
# The streaming method.
# Can be either 'php' (default), 'x-sendfile', or 'x-accel-redirect'
# See https://github.com/phanan/koel/wiki#streaming-music for more information.
# Note: This setting doesn't have effect if the media needs transcoding (e.g. FLAC).
STREAMING_METHOD=php
@ -33,11 +37,23 @@ STREAMING_METHOD=php
LASTFM_API_KEY=
LASTFM_API_SECRET=
# You can also configure Koel to use a CDN to serve the media files.
# This url must be mapped to the home URL of your Koel's installation.
# No trailing slash, please.
CDN_URL=
# If you want to transcode FLAC to MP3 and stream it on the fly, make sure the
# settings here are sane.
# The full path of ffmpeg binary. Make sure it's executable by the web user.
FFMPEG_PATH=/usr/local/bin/ffmpeg
# The bit rate of the out mp3 stream. Higher value results in better quality,
# but bigger file and more bandwidth.
OUTPUT_BIT_RATE=128
# The variables below are Laravel-specific.
# You can change them if you know what you're doing. Otherwise, just leave them as-is.

View file

@ -5,6 +5,7 @@ namespace App\Http\Controllers\API;
use App\Http\Streamers\PHPStreamer;
use App\Http\Streamers\XAccelRedirectStreamer;
use App\Http\Streamers\XSendFileStreamer;
use App\Http\Streamers\TranscodingStreamer;
use App\Models\Song;
class SongController extends Controller
@ -18,6 +19,10 @@ class SongController extends Controller
*/
public function play(Song $song)
{
if (ends_with(mime_content_type($song->path), 'flac')) {
return (new TranscodingStreamer($song))->stream();
}
switch (env('STREAMING_METHOD')) {
case 'x-sendfile':
return (new XSendFileStreamer($song))->stream();

View file

@ -0,0 +1,49 @@
<?php
namespace App\Http\Streamers;
use App\Models\Song;
class TranscodingStreamer extends BaseStreamer implements StreamerInterface
{
public function __construct(Song $song)
{
parent::__construct($song);
}
/**
* On-the-fly stream the current song while transcoding.
*/
public function stream()
{
if (!is_executable($ffmpeg = env('FFMPEG_PATH', '/usr/local/bin/ffmpeg'))) {
abort(500, 'Transcoding requires valid ffmpeg settings.');
}
$bitRate = filter_var(env('OUTPUT_BIT_RATE', 128), FILTER_SANITIZE_NUMBER_INT);
// Since we can't really know the content length of a file while it's still being transcoded,
// "calculating" it (like below) will be much likely to result in net::ERR_CONTENT_LENGTH_MISMATCH errors.
// Better comment these for now.
//
// header('Accept-Ranges: bytes');
// $bytes = round(($this->song->length * $bitRate * 1024) / 8);
// header("Content-Length: $bytes");
header('Content-Type: audio/mpeg');
header('Content-Disposition: attachment; filename="'.basename($this->song->path).'"');
$args = [
'-i '.escapeshellarg($this->song->path),
'-map 0:0',
'-v 0',
"-ab {$bitRate}k",
'-f mp3',
'-',
];
passthru("$ffmpeg ".implode($args, ' '));
return;
}
}

View file

@ -46,7 +46,7 @@ class Media
'ugly' => [], // Unmodified files
];
$files = Finder::create()->files()->name('/\.(mp3|ogg|m4a)$/i')->in($path);
$files = Finder::create()->files()->name('/\.(mp3|ogg|m4a|flac)$/i')->in($path);
foreach ($files as $file) {
$song = $this->syncFile($file);

144
composer.lock generated
View file

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "73595742c708c946629155b84a000a62",
"content-hash": "b4898021e96521543995ae80b2a17399",
"hash": "ed1a234d6513d5a7614be084578c3bd7",
"content-hash": "af504fd25aa5ea944786ee8288568758",
"packages": [
{
"name": "barryvdh/laravel-ide-helper",
@ -70,6 +70,54 @@
],
"time": "2015-12-21 19:48:06"
},
{
"name": "captbaritone/transcode-to-mp3-stream",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/captbaritone/transcode-to-mp3-stream.git",
"reference": "ad66ccad3a86d6ada4158f59a6e179eb359b89b7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/captbaritone/transcode-to-mp3-stream/zipball/ad66ccad3a86d6ada4158f59a6e179eb359b89b7",
"reference": "ad66ccad3a86d6ada4158f59a6e179eb359b89b7",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"mockery/mockery": "dev-master"
},
"type": "library",
"autoload": {
"psr-0": {
"Captbaritone\\TranscodeToMp3Stream": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordan Eldredge",
"email": "jordanEldredge@gmail.com",
"homepage": "http://jordaneldredge.com",
"role": "Developer"
}
],
"description": "Transcode various audio formats to mp3 streams on the fly",
"homepage": "http://github.com/captbaritone/transcode-to-mp3-stream",
"keywords": [
"audio",
"mp3",
"stream",
"transcode"
],
"time": "2016-01-25 15:31:23"
},
{
"name": "classpreloader/classpreloader",
"version": "3.0.0",
@ -339,16 +387,16 @@
},
{
"name": "guzzlehttp/psr7",
"version": "1.2.1",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982"
"reference": "f5d04bdd2881ac89abde1fb78cc234bce24327bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/4d0bdbe1206df7440219ce14c972aa57cc5e4982",
"reference": "4d0bdbe1206df7440219ce14c972aa57cc5e4982",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/f5d04bdd2881ac89abde1fb78cc234bce24327bb",
"reference": "f5d04bdd2881ac89abde1fb78cc234bce24327bb",
"shasum": ""
},
"require": {
@ -393,7 +441,7 @@
"stream",
"uri"
],
"time": "2015-11-03 01:34:55"
"time": "2016-01-23 01:23:02"
},
{
"name": "jakub-onderka/php-console-color",
@ -578,16 +626,16 @@
},
{
"name": "laravel/framework",
"version": "v5.2.6",
"version": "v5.2.12",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "b774c304ee81fcf5402fa06b261b364ba8f29cf0"
"reference": "6b6255ad7bfbdb721b8d00b09d52b146c5d363d7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/b774c304ee81fcf5402fa06b261b364ba8f29cf0",
"reference": "b774c304ee81fcf5402fa06b261b364ba8f29cf0",
"url": "https://api.github.com/repos/laravel/framework/zipball/6b6255ad7bfbdb721b8d00b09d52b146c5d363d7",
"reference": "6b6255ad7bfbdb721b8d00b09d52b146c5d363d7",
"shasum": ""
},
"require": {
@ -702,7 +750,7 @@
"framework",
"laravel"
],
"time": "2015-12-31 17:41:58"
"time": "2016-01-26 04:15:37"
},
{
"name": "league/flysystem",
@ -867,23 +915,23 @@
},
{
"name": "mtdowling/cron-expression",
"version": "v1.0.4",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/mtdowling/cron-expression.git",
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412"
"reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412",
"reference": "fd92e883195e5dfa77720b1868cf084b08be4412",
"url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
"reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*"
"phpunit/phpunit": "~4.0|~5.0"
},
"type": "library",
"autoload": {
@ -907,7 +955,7 @@
"cron",
"schedule"
],
"time": "2015-01-11 23:07:46"
"time": "2016-01-26 21:23:30"
},
{
"name": "namshi/jose",
@ -1059,16 +1107,16 @@
},
{
"name": "paragonie/random_compat",
"version": "1.1.4",
"version": "1.1.5",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "d762ee5b099a29044603cd4649851e81aa66cb47"
"reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/d762ee5b099a29044603cd4649851e81aa66cb47",
"reference": "d762ee5b099a29044603cd4649851e81aa66cb47",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/dd8998b7c846f6909f4e7a5f67fabebfc412a4f7",
"reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7",
"shasum": ""
},
"require": {
@ -1103,7 +1151,7 @@
"pseudorandom",
"random"
],
"time": "2015-12-10 14:48:13"
"time": "2016-01-06 13:31:20"
},
{
"name": "phanan/cascading-config",
@ -1514,16 +1562,16 @@
},
{
"name": "symfony/class-loader",
"version": "v2.8.1",
"version": "v2.8.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
"reference": "ec74b0a279cf3a9bd36172b3e3061591d380ce6c"
"reference": "98e9089a428ed0e39423b67352c57ef5910a3269"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/ec74b0a279cf3a9bd36172b3e3061591d380ce6c",
"reference": "ec74b0a279cf3a9bd36172b3e3061591d380ce6c",
"url": "https://api.github.com/repos/symfony/class-loader/zipball/98e9089a428ed0e39423b67352c57ef5910a3269",
"reference": "98e9089a428ed0e39423b67352c57ef5910a3269",
"shasum": ""
},
"require": {
@ -1562,7 +1610,7 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "https://symfony.com",
"time": "2015-12-05 17:37:59"
"time": "2016-01-03 15:33:41"
},
{
"name": "symfony/console",
@ -1926,16 +1974,16 @@
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.0.1",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25"
"reference": "1289d16209491b584839022f29257ad859b8532d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/49ff736bd5d41f45240cec77b44967d76e0c3d25",
"reference": "49ff736bd5d41f45240cec77b44967d76e0c3d25",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
"reference": "1289d16209491b584839022f29257ad859b8532d",
"shasum": ""
},
"require": {
@ -1947,7 +1995,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
"dev-master": "1.1-dev"
}
},
"autoload": {
@ -1981,20 +2029,20 @@
"portable",
"shim"
],
"time": "2015-11-20 09:19:13"
"time": "2016-01-20 09:13:37"
},
{
"name": "symfony/polyfill-php56",
"version": "v1.0.1",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php56.git",
"reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f"
"reference": "4d891fff050101a53a4caabb03277284942d1ad9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/e2e77609a9e2328eb370fbb0e0d8b2000ebb488f",
"reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f",
"url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/4d891fff050101a53a4caabb03277284942d1ad9",
"reference": "4d891fff050101a53a4caabb03277284942d1ad9",
"shasum": ""
},
"require": {
@ -2004,7 +2052,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
"dev-master": "1.1-dev"
}
},
"autoload": {
@ -2037,20 +2085,20 @@
"portable",
"shim"
],
"time": "2015-12-18 15:10:25"
"time": "2016-01-20 09:13:37"
},
{
"name": "symfony/polyfill-util",
"version": "v1.0.1",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-util.git",
"reference": "4271c55cbc0a77b2641f861b978123e46b3da969"
"reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-util/zipball/4271c55cbc0a77b2641f861b978123e46b3da969",
"reference": "4271c55cbc0a77b2641f861b978123e46b3da969",
"url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
"reference": "8de62801aa12bc4dfcf85eef5d21981ae7bb3cc4",
"shasum": ""
},
"require": {
@ -2059,7 +2107,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
"dev-master": "1.1-dev"
}
},
"autoload": {
@ -2089,7 +2137,7 @@
"polyfill",
"shim"
],
"time": "2015-11-04 20:28:58"
"time": "2016-01-20 09:13:37"
},
{
"name": "symfony/process",
@ -3745,7 +3793,9 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"captbaritone/transcode-to-mp3-stream": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {