Passed
Push — master ( c9bc4c...55b9e7 )
by Sébastien
04:18 queued 22s
created

ScanCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @see       https://github.com/soluble-io/soluble-mediatools-cli for the canonical repository
7
 *
8
 * @copyright Copyright (c) 2018-2019 Sébastien Vanvelthem. (https://github.com/belgattitude)
9
 * @license   https://github.com/soluble-io/soluble-mediatools-cli/blob/master/LICENSE.md MIT
10
 */
11
12
namespace Soluble\MediaTools\Cli\Command;
13
14
use ScriptFUSION\Byte\ByteFormatter;
15
use Soluble\MediaTools\Cli\Exception\MissingFFProbeBinaryException;
16
use Soluble\MediaTools\Cli\FileSystem\DirectoryScanner;
17
use Soluble\MediaTools\Cli\Media\FileExtensions;
18
use Soluble\MediaTools\Video\Exception as VideoException;
19
use Soluble\MediaTools\Video\SeekTime;
20
use Soluble\MediaTools\Video\VideoInfoReaderInterface;
21
use Symfony\Component\Console\Command\Command;
22
use Symfony\Component\Console\Helper\ProgressBar;
23
use Symfony\Component\Console\Helper\Table;
24
use Symfony\Component\Console\Helper\TableCell;
25
use Symfony\Component\Console\Helper\TableSeparator;
26
use Symfony\Component\Console\Helper\TableStyle;
27
use Symfony\Component\Console\Input\InputDefinition;
28
use Symfony\Component\Console\Input\InputInterface;
29
use Symfony\Component\Console\Input\InputOption;
30
use Symfony\Component\Console\Output\OutputInterface;
31
32
class ScanCommand extends Command
33
{
34
    /** @var VideoInfoReaderInterface */
35
    private $reader;
36
37
    /** @var string[] */
38
    private $supportedVideoExtensions;
39
40 4
    public function __construct(VideoInfoReaderInterface $videoInfoReader)
41
    {
42 4
        $this->reader                   = $videoInfoReader;
43 4
        $this->supportedVideoExtensions = (new FileExtensions())->getMediaExtensions();
44 4
        parent::__construct();
45 4
    }
46
47
    /**
48
     * Configures the command.
49
     */
50 4
    protected function configure(): void
51
    {
52
        $this
53 4
            ->setName('scan:videos')
54 4
            ->setDescription('Scan for video')
55 4
            ->setDefinition(
56 4
                new InputDefinition([
57 4
                    new InputOption('dir', 'd', InputOption::VALUE_REQUIRED),
58
                ])
59
            );
60 4
    }
61
62 4
    protected function execute(InputInterface $input, OutputInterface $output): int
63
    {
64 4
        if (!$input->hasOption('dir')) {
65
            throw new \InvalidArgumentException('Missing dir argument, use <command> <dir>');
66
        }
67 4
        $videoPath = $input->hasOption('dir') ? $input->getOption('dir') : null;
68 4
        if (!is_string($videoPath) || !is_dir($videoPath)) {
69 2
            throw new \InvalidArgumentException(sprintf(
70 2
                'Video dir %s does not exists',
71 2
                is_string($videoPath) ? $videoPath : json_encode($videoPath)
72
            ));
73
        }
74
75 2
        $output->writeln(sprintf('* Scanning %s for files...', $videoPath));
76
77
        // Get the videos in path
78 2
        $videos = (new DirectoryScanner())->findFiles($videoPath, $this->supportedVideoExtensions);
79
80 2
        $output->writeln('* Reading metadata...');
81
82 2
        $progressBar = new ProgressBar($output, count($videos));
83 2
        $progressBar->start();
84
85 2
        $bitRateFormatter = new ByteFormatter();
86 2
        $sizeFormatter    = new ByteFormatter();
87
88 2
        $rows      = [];
89 2
        $warnings  = [];
90 2
        $totalSize = 0;
91
92
        /** @var \SplFileInfo $video */
93 2
        foreach ($videos as $video) {
94 2
            $videoFile = $video->getPathname();
95
            try {
96 2
                $info     = $this->reader->getInfo($videoFile);
97 1
                $vStream  = $info->getVideoStreams()->getFirst();
98 1
                $aStream  = $info->getAudioStreams()->getFirst();
99 1
                $pixFmt   = $vStream->getPixFmt();
100 1
                $bitRate  = $vStream->getBitRate();
101 1
                $fileSize = $video->getSize();
102
103 1
                $fps = (string) ($vStream->getFps(0) ?? '');
104
105
                $row = [
106 1
                    'video'      => $video,
107 1
                    'duration'   => preg_replace('/\.([0-9])+$/', '', SeekTime::convertSecondsToHMSs(round($info->getDuration(), 1))),
108 1
                    'codec'      => sprintf('%s/%s', $vStream->getCodecName(), $aStream->getCodecName()),
109 1
                    'resolution' => sprintf(
110 1
                        '%sx%s%s',
111 1
                        $vStream->getWidth(),
112 1
                        $vStream->getHeight(),
113 1
                        $fps !== '' ? " <fg=yellow>${fps}fps</>" : ''
114
                    ),
115 1
                    'bitrate' => ($bitRate > 0 ? $bitRateFormatter->format((int) $bitRate) . '/s' : ''),
116 1
                    'size'    => $sizeFormatter->format($fileSize),
117 1
                    'pixFmt'  => $pixFmt,
118
                ];
119 1
                $rows[] = $row;
120 1
                $totalSize += $fileSize;
121 2
            } catch (VideoException\MissingFFProbeBinaryException $e) {
122 1
                throw new MissingFFProbeBinaryException('Unable to run ffprobe binary, check your config and ensure it\'s properly installed');
123 1
            } catch (VideoException\InfoReaderExceptionInterface $e) {
124 1
                $warnings[] = [$videoFile];
125
            }
126
127 1
            $progressBar->advance();
128
        }
129 1
        $progressBar->finish();
130
131 1
        $output->writeln('');
132 1
        $output->writeln('* Available media files:');
133
134 1
        $this->renderResultsTable($output, $rows, $totalSize);
135
136
        // display warnings
137 1
        if (count($warnings) > 0) {
138 1
            $output->writeln('* The following files were not detected as valid medias:');
139 1
            $table = new Table($output);
140 1
            $table->setHeaders([
141 1
                'Unsupported files',
142
            ]);
143 1
            $table->setStyle('box-double');
144 1
            $table->setRows($warnings);
145 1
            $table->render();
146
        }
147
148 1
        $output->writeln('');
149
150 1
        return 0;
151
    }
152
153 1
    private function renderResultsTable(OutputInterface $output, array $rows, int $totalSize, array $columns = []): void
0 ignored issues
show
Unused Code introduced by
The parameter $columns is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

153
    private function renderResultsTable(OutputInterface $output, array $rows, int $totalSize, /** @scrutinizer ignore-unused */ array $columns = []): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
    {
155 1
        $sizeFormatter = new ByteFormatter();
156
157 1
        $table = new Table($output);
158
159 1
        $rightAlignstyle = new TableStyle();
160 1
        $rightAlignstyle->setPadType(STR_PAD_LEFT);
161
162
        //$table->setStyle($tableStyle);
163 1
        $table->setStyle('box');
164 1
        $table->setHeaders([
165 1
            'file',
166
            'duration',
167
            'codec',
168
            'size',
169
            'bitrate',
170
            'filesize',
171
            'pix_fmt',
172
        ]);
173
174 1
        foreach ($colIndexes = [1, 2, 3, 4, 5] as $idx) {
0 ignored issues
show
Unused Code introduced by
The assignment to $colIndexes is dead and can be removed.
Loading history...
175 1
            $table->setColumnStyle($idx, $rightAlignstyle);
176
        }
177
178 1
        $previousPath = null;
179 1
        $first        = true;
180
181 1
        foreach ($rows as $idx => $row) {
182
            /** @var \SplFileInfo $file */
183 1
            $file         = $row['video'];
184 1
            $fileName     = $file->getBasename();
185 1
            $fileName     = mb_strlen($fileName) > 30 ? mb_substr($file->getBasename(), 0, 30) . '[...].' . $file->getExtension() : $fileName;
186 1
            $row['video'] = $fileName;
187 1
            if ($previousPath !== $file->getPath()) {
188 1
                if (!$first) {
189
                    $table->addRow(new TableSeparator(['colspan' => count($row)]));
190
                }
191 1
                $table->addRow([new TableCell(sprintf('<fg=yellow>%s</>', $file->getPath()), ['colspan' => count($row)])]);
192 1
                $table->addRow(new TableSeparator(['colspan' => count($row)]));
193 1
                $previousPath = $file->getPath();
194
            }
195 1
            $table->addRow($row);
196 1
            $first = false;
197
        }
198
199 1
        $table->addRow(new TableSeparator());
200 1
        $table->addRow(['<fg=cyan>Total</>', '', '', '', '', sprintf('<fg=cyan>%s</>', $sizeFormatter->format($totalSize))]);
201
202 1
        $table->render();
203 1
    }
204
}
205