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); +} + +?> + + + + + + Daniel's YouTube Downloader + + + + + + + +
+
+ + required="required" class="form-control" /> + + Service Status +
+
+ +
+ + + + + diff --git a/info.php b/info.php new file mode 100755 index 0000000..fe156b0 --- /dev/null +++ b/info.php @@ -0,0 +1,61 @@ + + + Daniel's YouTube Downloader + + + +
+ Back + + + + +$line) { + if($i == 0) { + $columns = preg_split('/ +/', $line); + foreach($columns as $column) { + echo ' \n"; + } + echo " \n"; + echo " \n"; + echo " \n"; + + for($i = 1; $i < count($columns); $i++) { + $regExpr .= '([^ ]+) +'; + } + $regExpr .= '(.*)$'; + } else { + //if(strpos($line, "youtube-dl") === FALSE) { + // continue; + //} + + if(!preg_match('/' . $regExpr . '/', $line, $matches)) { + continue; + } + + array_shift($matches); + + if($matches[0] != 'www-data') { + continue; + } + + echo " \n"; + + foreach($matches as $match) { + echo ' \n"; + } + + echo " \n"; + } + } + ?> + +
' . htmlentities($column) . "
' . htmlentities($match) . "
+
+ + diff --git a/script.js b/script.js new file mode 100644 index 0000000..50feab7 --- /dev/null +++ b/script.js @@ -0,0 +1,122 @@ +jQuery(document).ready(function($){ + $('form').submit(function(e) { + e.preventDefault(); + + var resultWrapper, result, resultHeader, resultBody, resultContent; + $('#results').append(resultWrapper = $('
') + .addClass('col-xl-3 col-md-4 col-sm-6 col-12') + .append(result = $('
') + .addClass('card text-white bg-secondary') + .append(resultHeader = $('
') + .addClass('card-header') + .text($("input[name=url]").val() + ' ') + .append($('') + .text($('select[name=option] option:selected').text()) + ) + ) + .append(resultBody = $('
') + .addClass('card-body') + .append(resultContent = $('
')
+                    )
+                )
+            )
+        );
+
+        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