Files
torsearch/src/Download/Downloader/ProcessDownloader.php

108 lines
3.8 KiB
PHP

<?php
namespace App\Download\Downloader;
use App\Base\Service\MediaFiles;
use App\Download\Framework\Entity\Download;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
use Symfony\Contracts\Cache\CacheInterface;
class ProcessDownloader implements DownloaderInterface
{
/**
* @var RedisAdapter $cache
*/
public function __construct(
private EntityManagerInterface $entityManager,
private MediaFiles $mediaFiles,
private CacheInterface $cache,
) {}
/**
* @inheritDoc
*/
public function download(string $mediaType, string $title, string $url, ?int $downloadId): void
{
/** @var Download $downloadEntity */
$downloadEntity = $this->entityManager->getRepository(Download::class)->find($downloadId);
$this->entityManager->flush();
$downloadPreferences = $downloadEntity->getUser()->getDownloadPreferences();
$path = $this->getDownloadPath($mediaType, $title, $downloadPreferences);
$processArgs = ['wget', '-O', $downloadEntity->getFilename(), $url];
if ($downloadEntity->getStatus() === 'Paused') {
$downloadEntity->setStatus('In Progress');
$processArgs = ['wget', '-c', '-O', $downloadEntity->getFilename(), $url];
} else {
$downloadEntity->setProgress(0);
}
fwrite(STDOUT, implode(" ", $processArgs));
$process = (new Process($processArgs))->setWorkingDirectory($path);
$process->setTimeout(1800); // 30 min
$process->setIdleTimeout(600); // 10 min
$process->start();
try {
$progress = 0;
$this->entityManager->flush();
$process->wait(function ($type, $buffer) use ($progress, $downloadEntity, $process): void {
// The PauseDownloadHandler will set this to 'true'
$doPause = $this->cache->getItem('download.pause.' . $downloadEntity->getId());
if (true === $doPause->isHit() && true === $doPause->get()) {
$downloadEntity->setStatus('Paused');
$this->cache->deleteItem('download.pause.' . $downloadEntity->getId());
$this->entityManager->flush();
$process->stop();
}
if (Process::ERR === $type) {
$pregMatchOutput = [];
preg_match('/[\d]+%/', $buffer, $pregMatchOutput);
if (!empty($pregMatchOutput)) {
if ($pregMatchOutput[0] !== $progress) {
$progress = (int) $pregMatchOutput[0];
$downloadEntity->setProgress($progress);
$this->entityManager->flush();
}
}
}
fwrite(STDOUT, $buffer);
});
if ($downloadEntity->getStatus() !== 'Paused') {
$downloadEntity->setProgress(100);
}
} catch (ProcessFailedException $exception) {
$downloadEntity->setStatus('Failed');
}
$this->entityManager->flush();
}
public function getDownloadPath(string $mediaType, string $title, array $downloadPreferences): string
{
if ($mediaType === 'movies') {
if ((bool) $downloadPreferences['movie_folder']->getPreferenceValue() === true) {
return $this->mediaFiles->createMovieDirectory($title);
}
return $this->mediaFiles->getMoviesPath();
}
if ($mediaType === 'tvshows') {
return $this->mediaFiles->createTvShowDirectory($title);
}
throw new \Exception("There is no download path for media type: $mediaType");
}
}