diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9d30a54 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +/Dockerfile +/LICENSE +/README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..976837a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM php:7.0-apache + +RUN apt update \ + && apt install youtube-dl -y \ + && rm /var/lib/apt/lists/* /var/log/* -Rf + +ADD . /var/www/html + +VOLUME ["/var/www/html/files"] diff --git a/index.php b/index.php new file mode 100755 index 0000000..66cd975 --- /dev/null +++ b/index.php @@ -0,0 +1,132 @@ + [ + 'name' => 'Audio Only (MP3)', + 'group' => 'Audio Only', + 'option' => '-k -x --audio-format mp3 --audio-quality 0', + 'cache' => '*-%youtubeid%.mp3' + ], + "audio_flac" => [ + 'name' => 'Audio Only (FLAC)', + 'group' => 'Audio Only', + 'option' => '-k -x --audio-format flac --audio-quality 0', + 'cache' => '*-%youtubeid%.flac' + ], + "best_video_audio" => [ + 'name' => 'Combine best Video+Audio', + 'group' => NULL, + 'option' => '-k', + 'cache' => NULL + ] +]; + +if(!chdir('files')) { + die('could not enter files folder'); +} + +if($_SERVER['REQUEST_METHOD'] == 'POST') { + if(!isset($_POST['option'], $_POST['url'])) { + http_response_code(400); + die('not all required values set!'); + } + + if(empty($option = trim($_POST['option'])) || + empty($url = trim($_POST['url']))) { + http_response_code(400); + die('url empty!'); + } + + if(!filter_var($url, FILTER_VALIDATE_URL)) { + http_response_code(400); + die('invalid url!'); + } + + if(!isset($options[$option])) { + http_response_code(400); + die('invalid option!'); + } + + $option = $options[$option]; + + preg_match("#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&\n]+(?=\?)|(?<=v=)[^&\n]+|(?<=youtu.be/)[^&\n]+#", $url, $matches); + if(count($matches) != 1) { + http_response_code(400); + die('invalid youtube url!' . count($matches)); + } + + $cached = false; + + if(!is_null($option['cache'])) { + foreach(glob(str_replace("%youtubeid%", $matches[0], $option['cache'])) as $file) { + echo '[cache] Destination: ' . $file . "\n"; + $cached = true; + } + } + + if($cached) { + die('exit code: 0'); + } + + ini_set('output_buffering', 'off'); + ini_set('zlib.output_compression', false); + ini_set('implicit_flush', true); + ob_implicit_flush(true); + while (ob_get_level() > 0) { + $level = ob_get_level(); + ob_end_clean(); + if (ob_get_level() == $level) break; + } + if (function_exists('apache_setenv')) { + apache_setenv('no-gzip', '1'); + apache_setenv('dont-vary', '1'); + } + set_time_limit(0); + + system('youtube-dl ' . $option['option']. ' ' . $url . ' 2>&1', $exitCode); + die('exit code: ' . $exitCode); +} + +?> + +
+ + + +' . htmlentities($column) . " | \n"; + } + echo "
---|
' . htmlentities($match) . " | \n"; + } + + echo "
') + ) + ) + ) + ); + + function formatText(text) { + var result = ""; + for(var line of text.split("\n")) { + var parts = line.split("\r"); + result += parts[parts.length - 1] + "\n"; + } + return result; + } + + $.ajax({ + 'url': $('form').attr('action'), + 'method': $('form').attr('method'), + 'data': (function() { + var data = {}; + $('form input, form select').each(function(){ + data[$(this).attr('name')] = $(this).val(); + }); + return data; + })(), + 'processData': true, + 'contentType': 'application/x-www-form-urlencoded; charset=UTF-8', + 'xhr': function() { + var xhr = new XMLHttpRequest(); + + xhr.addEventListener('progress', function(e) { + resultContent.text(formatText(e.target.response)); + }, false); + + return xhr; + }, + 'success': function(data) { + resultContent.text(formatText(data)); + + result + .removeClass('bg-warning') + + if(data.indexOf('exit code: 0') == -1) { + result + .addClass('bg-danger') + .append($('').text('There was an error while processing your request!')); + return; + } + + var anyLink = false; + + for(regex of [ + /Destination: ([^\n\r$]*)/g, + / ([^ ]+) has already been downloaded and merged/g + ]) { + var match; + while (match = regex.exec(data)) { + if(anyLink) { + resultBody.append($('
')); + } + + resultBody.append($('') + .addClass('btn btn-sm btn-primary') + .attr('href', 'files/' + match[1]) + .text(match[1]) + ); + + anyLink = true; + } + } + + if(anyLink) { + result + .addClass('bg-success'); + } else { + result + .addClass('bg-danger') + .append($('').text('Did not find any downloadable file!')); + } + + }, + 'error': function(jqXHR, textStatus, errorThrown) { + resultContent.text(formatText(jqXHR.responseText)); + + result + .removeClass('alert-warning') + .addClass('alert-danger') + .append($('
').text('Request failed!')); + }, + 'complete': function() { + resultHeader.prepend($('') + .html('×') + .addClass('float-right btn btn-sm btn-danger') + .attr('href', '#') + .click(function(e) { + e.preventDefault(); + + resultWrapper.remove(); + }) + ) + } + }); + }) +}); \ No newline at end of file