108 lines
3.8 KiB
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");
|
|
}
|
|
} |