youtube-dl download progress bar with PHP

Displaying a progress bar for a youtube-dl download by using PHP and some AJAX setinterval. I have covered AJAX setinterval before with an FFmpeg progress bar and a general continuous AJAX get.

Now for a youtube-dl download progress bar, the only real point of difference is the parsing of the youtube-dl output file which has the progress log.

A youtube-dl output line looks like this

[download]  35.5% of 293.09MiB at  9.75MiB/s ETA 00:19

Putting the read last line from file code into a function and splitting it into an array based on the spaces. This makes for a consistent way to split the output into progress %, total video size, download speed and ETA… if you ever needed those values.

get-progress.php:

<?php
$log_file_path = 'yt-dl-progress.txt';

function lineAsArray(string $filepath): array
{
    $line = '';
    $f = fopen($filepath, 'r');
    $cursor = -1;
    fseek($f, $cursor, SEEK_END);
    $char = fgetc($f);
    while ($char === "\n" || $char === "\r") {
        fseek($f, $cursor--, SEEK_END);
        $char = fgetc($f);
    }
    while ($char !== false && $char !== "\n" && $char !== "\r") {
        $line = $char . $line;
        fseek($f, $cursor--, SEEK_END);
        $char = fgetc($f);
    }
    $remove_whitespace = preg_replace('/\s+/', ' ', $line);
    return explode(" ", $remove_whitespace);
}

function progress(array $array): string
{
    return str_replace('%', '', $array[1]);
}

$last_line = lineAsArray($log_file_path);

echo progress($last_line);

This simply returns a float for the percentage of the download task completed.

index.html:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.0/css/bootstrap.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript">
    setInterval(function () {
        $.ajax({
            url: 'get-progress.php',
            success: function (data) {
                $('#progress-string').html(`${data}%`);
                $('#progressbar').attr('aria-valuenow', data).css('width', `${data}%`);
            }
        });
    }, 1000);
</script>
<div class="container">
    <div class="row">
        <div class="col-12">
            <div class="card">
                <div class="progress">
                    <div id="progressbar" class="progress-bar bg-info" role="progressbar" aria-valuenow="0"
                         aria-valuemin="0" aria-valuemax="100"><span id="progress-string"></span></div>
                </div>
            </div>
        </div>
    </div>
</div>

This is what fetches every 1 second, the download percent from get-progress.php and then uses its value to fill the progress bar and display the value.

Sample youtube-dl command with output to file :

sudo nohup youtube-dl --merge-output-format mp4 -f best -o savevideas.mp4 'https://www.youtube.com/watch?v=XXXXXX' > yt-dl-progress.txt

This whole operation only works if you’re saving the youtube-dl command to an output file, as the above command does.