Simultaneous downloads !

Better error management
Musics are now dissociate from videos
This commit is contained in:
p1rox 2015-03-12 21:47:23 +01:00
parent 5e17a6e8bf
commit bdd3bc126c
8 changed files with 166 additions and 39 deletions

View file

@ -4,13 +4,16 @@
![List](https://github.com/p1rox/Youtube-dl-WebUI/raw/master/img/list.png)
## Description
Youtube-dl WebUI is a small web interface for youtube-dl. It allows you to host your own video downloader. After the download you can stream your videos from your web browser or save it on your computer directly from the list page.
Youtube-dl WebUI is a small web interface for youtube-dl. It allows you to host your own video downloader.
After the download you can stream your videos from your web browser or save it on your computer directly from the list page.
It supports simultaneous downloads in background.
### You can now extract the audio of a video and download multiple videos at the same time !
## Requirements
- A web server (Apache or nginx)
- PHP latest version should be fine.
- Python 2.7 for Youtube-dl
- [Youtube-dl](https://github.com/rg3/youtube-dl)
- avconv or other is required for audio extraction (from youtube-dl doc) :
`-x, --extract-audio convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)`

View file

@ -5,6 +5,7 @@ class Downloader
private $urls = [];
private $config = [];
private $audio_only = false;
private $errors = [];
public function __construct($post, $audio_only)
{
@ -13,22 +14,59 @@ class Downloader
if($this->is_installed() != 0)
{
die("youtube-dl is not installed !");
$errors[] = "Youtube-dl is not installed, see <a>https://rg3.github.io/youtube-dl/download.html</a> !";
}
if(!$this->outuput_folder_exists())
{
die("Output folder doesn't exist !");
$errors[] = "Output folder doesn't exist !";
}
if($this->is_extracter_installed())
if($audio_only && $this->is_extracter_installed())
{
die("Install and configure an extracter !");
$errors[] = "Install an audio extracter (ex: avconv) !";
}
if(isset($errors) && count($errors) > 0)
{
$_SESSION['errors'] = $errors;
return;
}
$this->urls = explode(",", $post);
$this->do_download();
if($this->config["max_dl"] == 0)
{
$this->do_download();
}
elseif($this->config["max_dl"] > 0)
{
if($this->background_jobs() >= 0 && $this->background_jobs() < $this->config["max_dl"])
{
$this->do_download();
}
else
{
$errors[] = "Simultaneous downloads limit reached !";
}
}
if(isset($errors) && count($errors) > 0)
{
$_SESSION['errors'] = $errors;
return;
}
}
public static function background_jobs()
{
return shell_exec("ps aux | grep -v grep | grep youtube-dl | wc -l");
}
public static function max_jobs()
{
$config = require dirname(__DIR__).'/config/config.php';
return $config["max_dl"];
}
private function is_installed()
@ -65,23 +103,23 @@ class Downloader
private function do_download()
{
$cmd = "youtube-dl";
$cmd .= ' -o '.$this->config["outputFolder"].'/';
$cmd .= escapeshellarg('%(title)s-%(uploader)s.%(ext)s');
$cmd .= " -o ".$this->config["outputFolder"]."/";
$cmd .= escapeshellarg("%(title)s-%(uploader)s.%(ext)s");
if($this->audio_only)
{
$cmd .= ' -x ';
$cmd .= " -x ";
}
foreach($this->urls as $url)
{
$cmd .= ' '.$url;
$cmd .= " ".$url;
}
$cmd .= ' --restrict-filenames'; // --restrict-filenames is for specials chars
$cmd .= ' 2>&1';
$cmd .= " --restrict-filenames"; // --restrict-filenames is for specials chars
$cmd .= " > /dev/null & echo $!";
exec($cmd, $out, $ret);
shell_exec($cmd);
}
}

View file

@ -1,8 +1,10 @@
<?php
class VideoHandler
class FileHandler
{
private $config = [];
private $videos_ext = ".{avi,mp4,flv}";
private $musics_ext = ".{mp3,ogg}";
public function __construct()
{
@ -18,7 +20,7 @@ class VideoHandler
$folder = dirname(__DIR__).'/'.$this->config["outputFolder"].'/';
foreach(glob($folder.'*') as $file)
foreach(glob($folder.'*'.$this->videos_ext, GLOB_BRACE) as $file)
{
$video = [];
$video["name"] = str_replace($folder, "", $file);
@ -30,12 +32,46 @@ class VideoHandler
return $videos;
}
public function delete($id)
public function listMusics()
{
$musics = [];
if(!$this->outuput_folder_exists())
return;
$folder = dirname(__DIR__).'/'.$this->config["outputFolder"].'/';
foreach(glob($folder.'*'.$this->musics_ext, GLOB_BRACE) as $file)
{
$music = [];
$music["name"] = str_replace($folder, "", $file);
$music["size"] = $this->to_human_filesize(filesize($file));
$musics[] = $music;
}
return $musics;
}
public function delete($id, $type)
{
$folder = dirname(__DIR__).'/'.$this->config["outputFolder"].'/';
$i = 0;
foreach(glob($folder.'*') as $file)
if($type === 'v')
{
$exts = $this->videos_ext;
}
elseif($type === 'm')
{
$exts = $this->musics_ext;
}
else
{
return;
}
foreach(glob($folder.'*'.$exts, GLOB_BRACE) as $file)
{
if($i == $id)
{
@ -71,7 +107,7 @@ class VideoHandler
return $this->to_human_filesize(disk_free_space($this->config["outputFolder"]));
}
public function get_video_folder()
public function get_downloads_folder()
{
return $this->config["outputFolder"];
}

View file

@ -5,7 +5,8 @@
return array(
"security" => true,
"password" => "63a9f0ea7bb98050796b649e85481845",
"outputFolder" => "videos",
"extracter" => "avconv");
"outputFolder" => "downloads",
"extracter" => "avconv",
"max_dl" => 3);
?>

View file

@ -1,10 +1,10 @@
<?php
require 'class/Session.php';
require 'class/VideoHandler.php';
require 'class/FileHandler.php';
require 'class/Downloader.php';
$session = Session::getInstance();
$video = new VideoHandler;
$file = new FileHandler;
if(!$session->is_logged_in())
{
@ -22,14 +22,38 @@
}
$downloader = new Downloader($_POST['urls'], $audio_only);
header("Location: list.php");
if(!isset($_SESSION['errors']))
{
if($audio_only)
{
header("Location: list.php?type=m");
}
else
{
header("Location: list.php?type=v");
}
}
}
}
require 'views/header.php';
?>
<div class="container">
<br>
<br>
<h1>Download</h1>
<?php
if(isset($_SESSION['errors']) && $_SESSION['errors'] > 0)
{
foreach ($_SESSION['errors'] as $e)
{
echo "<div class=\"alert alert-warning\" role=\"alert\">$e</div>";
}
}
?>
<form id="download-form" class="form-horizontal" action="index.php" method="post">
<div class="form-group">
<div class="col-md-10">
@ -51,8 +75,9 @@
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">Info</h3></div>
<div class="panel-body">
<p>Free space : <?php echo $video->free_space(); ?></b></p>
<p>Download folder : <?php echo $video->get_video_folder(); ?></p>
<p><b>Background downloads : <?php echo Downloader::background_jobs()." / ".Downloader::max_jobs() ?> </b></p>
<p>Free space : <?php echo $file->free_space(); ?></b></p>
<p>Download folder : <?php echo $file->get_downloads_folder(); ?></p>
</div>
</div>
</div>
@ -72,5 +97,6 @@
</div>
</div>
<?php
unset($_SESSION['errors']);
require 'views/footer.php';
?>

View file

@ -1,31 +1,46 @@
<?php
require 'class/Session.php';
require 'class/VideoHandler.php';
require 'class/FileHandler.php';
$session = Session::getInstance();
$video = new VideoHandler;
$file = new FileHandler;
if(!$session->is_logged_in())
{
header("Location: login.php");
}
if(isset($_GET['type']) && !empty($_GET['type']))
{
$t = $_GET['type'];
if($t === 'v')
{
$type = "videos";
$files = $file->listVideos();
}
elseif($t === 'm')
{
$type = "musics";
$files = $file->listMusics();
}
}
if($session->is_logged_in() && isset($_GET["delete"]))
{
$video->delete($_GET["delete"]);
header("Location: list.php");
$file->delete($_GET["delete"], $t);
header("Location: list.php?type=".$t);
}
require 'views/header.php';
?>
<div class="container">
<h2>List of available videos :</h2>
<br>
<br>
<?php
$videos = $video->listVideos();
if(!empty($videos))
if(!empty($files))
{
?>
<h2>List of available <?php echo $type ?> :</h2>
<table class="table table-striped table-hover ">
<thead>
<tr>
@ -39,12 +54,12 @@
$i = 0;
$totalSize = 0;
foreach($videos as $v)
foreach($files as $f)
{
echo "<tr>";
echo "<td><a href=\"".$video->get_video_folder().'/'.$v["name"]."\" download>".$v["name"]."</a></td>";
echo "<td>".$v["size"]."</td>";
echo "<td><a href=\"./list.php?delete=$i\" class=\"btn btn-danger btn-sm\">Delete</a></td>";
echo "<td><a href=\"".$file->get_downloads_folder().'/'.$f["name"]."\" download>".$f["name"]."</a></td>";
echo "<td>".$f["size"]."</td>";
echo "<td><a href=\"./list.php?delete=$i&type=$t\" class=\"btn btn-danger btn-sm\">Delete</a></td>";
echo "</tr>";
$i++;
}
@ -55,7 +70,14 @@
}
else
{
echo "<br><div class=\"alert alert-warning\" role=\"alert\">No videos !</div>";
if(isset($t) && ($t === 'v' || $t === 'm'))
{
echo "<br><div class=\"alert alert-warning\" role=\"alert\">No $type !</div>";
}
else
{
echo "<br><div class=\"alert alert-warning\" role=\"alert\">No such type !</div>";
}
}
?>
<br/>

View file

@ -18,7 +18,8 @@
<div class="navbar-collapse collapse navbar-responsive-collapse">
<ul class="nav navbar-nav">
<li><a href="./">Download</a></li>
<li><a href="./list.php">List of videos</a></li>
<li><a href="./list.php?type=v">List of videos</a></li>
<li><a href="./list.php?type=m">List of musics</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<?php