Passed
Push — master ( d0bcc1...2a69c8 )
by Sébastien
02:28
created

VideoInfoReader::getInfo()   B

Complexity

Conditions 6
Paths 17

Size

Total Lines 32
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 6.0033

Importance

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