3 * Transcode audio file URLs to .mp3, cache them and stream them while
4 * transcoding is in progress.
6 require_once __DIR__ . '/../src/header.php';
8 if (!isset($_GET['url'])) {
9 errorOut('url parameter missing');
11 $parts = parse_url($_GET['url']);
12 if ($parts === false || !isset($parts['scheme'])) {
13 errorOut('Invalid URL');
15 if ($parts['scheme'] !== 'http' && $parts['scheme'] !== 'https') {
16 errorOut('URL is neither http nor https');
20 if (!is_dir($cacheDir)) {
21 errorOut('Cache dir does not exist');
23 if (!is_writable($cacheDir)) {
24 errorOut('Cache dir not writable');
27 $cacheFileName = str_replace(array(':', '/'), '-', $url) . '.mp3';
28 $cacheFilePath = $cacheDir . $cacheFileName;
30 if (file_exists($cacheFilePath)) {
31 header('HTTP/1.0 302 Moved Temporarily');
32 header('Location: ' . $cacheDirUrl . urlencode($cacheFileName));
38 . ' -i ' . escapeshellarg($url)
42 $descriptorspec = array(
43 1 => array('pipe', 'w'),// stdout is a pipe that the child will write to
44 2 => array('pipe', 'w')//stderr
47 register_shutdown_function('shutdown');
49 $process = proc_open($cmd, $descriptorspec, $pipes);
50 if (is_resource($process)) {
51 $tmpCacheFile = tempnam(sys_get_temp_dir(), 'transcode-cache-');
52 $cacheHdl = fopen($tmpCacheFile, 'wb');
53 header('Content-type: audio/mpeg');
54 while ($data = fread($pipes[1], 1000)) {
56 fwrite($cacheHdl, $data);
59 //TODO: maybe flush() and ob_flush();
62 $errors = stream_get_contents($pipes[2]);
65 $retval = proc_close($process);
69 rename($tmpCacheFile, $cacheFilePath);
71 header('HTTP/1.0 500 Internal Server Error');
72 header('Content-type: text/plain');
73 echo "Error transcoding\n";
75 unlink($tmpCacheFile);
81 global $process, $pipes, $tmpCacheFile;
83 if (connection_aborted()) {
84 //end ffmpeg and clean temp file
87 proc_terminate($process);
88 unlink($tmpCacheFile);
92 function errorOut($msg)
94 header('HTTP/1.0 400 Bad request');
95 header('Content-type: text/plain');