Passed
Push — master ( 89fbe5...c257f0 )
by Sébastien
02:18
created

VideoInfoReader::getSymfonyProcess()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 11
nc 1
nop 2
dl 0
loc 17
ccs 9
cts 9
cp 1
crap 1
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\MediaTools\Video;
6
7
use Psr\Log\LoggerInterface;
8
use Psr\Log\LogLevel;
9
use Psr\Log\NullLogger;
10
use Soluble\MediaTools\Common\Assert\PathAssertionsTrait;
11
use Soluble\MediaTools\Common\Exception\FileNotFoundException;
12
use Soluble\MediaTools\Common\Process\ProcessFactory;
13
use Soluble\MediaTools\Common\Process\ProcessParamsInterface;
14
use Soluble\MediaTools\Video\Config\FFProbeConfigInterface;
15
use Soluble\MediaTools\Video\Exception\InfoExceptionInterface;
16
use Soluble\MediaTools\Video\Exception\InfoProcessExceptionInterface;
17
use Soluble\MediaTools\Video\Exception\MissingInputFileException;
18
use Soluble\MediaTools\Video\Exception\ProcessFailedException;
19
use Soluble\MediaTools\Video\Exception\RuntimeException;
20
use Symfony\Component\Process\Exception as SPException;
21
use Symfony\Component\Process\Process;
22
23
class VideoInfoReader implements VideoInfoReaderInterface
24
{
25
    use PathAssertionsTrait;
26
27
    /** @var FFProbeConfigInterface */
28
    protected $ffprobeConfig;
29
30
    /** @var LoggerInterface|NullLogger */
31
    protected $logger;
32
33 4
    public function __construct(FFProbeConfigInterface $ffProbeConfig, ?LoggerInterface $logger = null)
34
    {
35 4
        $this->ffprobeConfig = $ffProbeConfig;
36 4
        $this->logger        = $logger ?? new NullLogger();
37 4
    }
38
39
    /**
40
     * Return ready-to-run symfony process object that you can use
41
     * to `run()` or `start()` programmatically. Useful if you want to make
42
     * things your way...
43
     *
44
     * @see https://symfony.com/doc/current/components/process.html
45
     */
46 2
    public function getSymfonyProcess(string $inputFile, ?ProcessParamsInterface $processParams = null): Process
47
    {
48 2
        $ffprobeCmd = trim(sprintf(
49 2
            '%s %s %s',
50 2
            $this->ffprobeConfig->getBinary(),
51 2
            implode(' ', [
52 2
                '-v quiet',
53
                '-print_format json',
54
                '-show_format',
55
                '-show_streams',
56
            ]),
57 2
            sprintf('-i %s', escapeshellarg($inputFile))
58
        ));
59
60 2
        $pp = $processParams ?? $this->ffprobeConfig->getProcessParams();
61
62 2
        return (new ProcessFactory($ffprobeCmd, $pp))();
63
    }
64
65
    /**
66
     * @throws InfoExceptionInterface
67
     * @throws InfoProcessExceptionInterface
68
     * @throws ProcessFailedException
69
     * @throws MissingInputFileException
70
     * @throws RuntimeException
71
     */
72 4
    public function getInfo(string $file): VideoInfo
73
    {
74
        try {
75
            try {
76 4
                $this->ensureFileExists($file);
77 2
                $process = $this->getSymfonyProcess($file);
78
79 2
                $process->mustRun();
80 1
                $output = $process->getOutput();
81 3
            } catch (FileNotFoundException $e) {
82 2
                throw new MissingInputFileException($e->getMessage());
83 1
            } catch (SPException\ProcessFailedException | SPException\ProcessTimedOutException | SPException\ProcessSignaledException $e) {
84 1
                throw new ProcessFailedException($e->getProcess(), $e);
85
            } catch (SPException\RuntimeException $e) {
86 1
                throw new RuntimeException($e->getMessage());
87
            }
88 3
        } catch (\Throwable $e) {
89 3
            $exceptionNs = explode('\\', get_class($e));
90 3
            $this->logger->log(
91 3
                ($e instanceof MissingInputFileException) ? LogLevel::WARNING : LogLevel::ERROR,
92 3
                sprintf(
93 3
                    'Video info retrieval failed \'%s\' with \'%s\'. "%s(%s)"',
94 3
                    $exceptionNs[count($exceptionNs) - 1],
95 3
                    __METHOD__,
96 3
                    $e->getMessage(),
97 3
                    $file
98
                )
99
            );
100 3
            throw $e;
101
        }
102
103 1
        return VideoInfo::createFromFFProbeJson($file, $output);
104
    }
105
}
106