Added Dockerfile and sources
This commit is contained in:
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@ -0,0 +1,3 @@
|
||||
/Dockerfile
|
||||
/LICENSE
|
||||
/README.md
|
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -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"]
|
132
index.php
Executable file
132
index.php
Executable file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
$options = [
|
||||
"audio_mp3" => [
|
||||
'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);
|
||||
}
|
||||
|
||||
?>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
|
||||
<title>Daniel's YouTube Downloader</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
|
||||
<style>
|
||||
pre {
|
||||
max-height: 100px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<form method="POST" class="form-inline">
|
||||
<select name="option" class="form-control">
|
||||
<?php $lastGroup = NULL; ?>
|
||||
<?php foreach($options as $index => $option) { ?>
|
||||
<?php if($option['group'] != $lastGroup) { ?>
|
||||
<?php if(!is_null($lastGroup)) { ?></optgroup><?php } ?>
|
||||
<?php if(!is_null($option['group'])) { ?><optgroup label="<?php echo htmlentities($option['group']); ?>"><?php } ?>
|
||||
<?php $lastGroup = $option['group']; ?>
|
||||
<?php } ?>
|
||||
<option value="<?php echo $index; ?>"><?php echo htmlentities($option['name']); ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
<input type="url" name="url" <?php if(isset($url)) { echo 'value="' . htmlentities($url) . '"'; } ?> required="required" class="form-control" />
|
||||
<button type="submit" class="btn btn-primary">Los</button>
|
||||
<a href="info.php">Service Status</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="row" id="results"></div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
61
info.php
Executable file
61
info.php
Executable file
@ -0,0 +1,61 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Daniel's YouTube Downloader</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<a href="index.php">Back</a>
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
$output = shell_exec('ps aux');
|
||||
$lines = explode("\n", $output);
|
||||
|
||||
$regExpr = "^";
|
||||
foreach($lines as $i=>$line) {
|
||||
if($i == 0) {
|
||||
$columns = preg_split('/ +/', $line);
|
||||
foreach($columns as $column) {
|
||||
echo ' <th>' . htmlentities($column) . "</th>\n";
|
||||
}
|
||||
echo " </tr>\n";
|
||||
echo " </thead>\n";
|
||||
echo " <tbody>\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 " <tr>\n";
|
||||
|
||||
foreach($matches as $match) {
|
||||
echo ' <td>' . htmlentities($match) . "</td>\n";
|
||||
}
|
||||
|
||||
echo " </tr>\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
122
script.js
Normal file
122
script.js
Normal file
@ -0,0 +1,122 @@
|
||||
jQuery(document).ready(function($){
|
||||
$('form').submit(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var resultWrapper, result, resultHeader, resultBody, resultContent;
|
||||
$('#results').append(resultWrapper = $('<div>')
|
||||
.addClass('col-xl-3 col-md-4 col-sm-6 col-12')
|
||||
.append(result = $('<div>')
|
||||
.addClass('card text-white bg-secondary')
|
||||
.append(resultHeader = $('<div>')
|
||||
.addClass('card-header')
|
||||
.text($("input[name=url]").val() + ' ')
|
||||
.append($('<small>')
|
||||
.text($('select[name=option] option:selected').text())
|
||||
)
|
||||
)
|
||||
.append(resultBody = $('<div>')
|
||||
.addClass('card-body')
|
||||
.append(resultContent = $('<pre>')
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
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($('<p>').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($('<br/>'));
|
||||
}
|
||||
|
||||
resultBody.append($('<a>')
|
||||
.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($('<p>').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($('<p>').text('Request failed!'));
|
||||
},
|
||||
'complete': function() {
|
||||
resultHeader.prepend($('<a>')
|
||||
.html('×')
|
||||
.addClass('float-right btn btn-sm btn-danger')
|
||||
.attr('href', '#')
|
||||
.click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
resultWrapper.remove();
|
||||
})
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
Reference in New Issue
Block a user