Failed Conditions
Push — master ( 874a26...b85ace )
by Sébastien
01:57
created

ScanCommand::execute()   C

Complexity

Conditions 12
Paths 123

Size

Total Lines 95
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 58
CRAP Score 12.017

Importance

Changes 0
Metric Value
cc 12
eloc 63
nc 123
nop 2
dl 0
loc 95
ccs 58
cts 61
cp 0.9508
crap 12.017
rs 6.2272
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Video\Exception as VideoException;
18
use Soluble\MediaTools\Video\SeekTime;
19
use Soluble\MediaTools\Video\VideoInfoReaderInterface;
20
use Symfony\Component\Console\Command\Command;
21
use Symfony\Component\Console\Helper\ProgressBar;
22
use Symfony\Component\Console\Helper\Table;
23
use Symfony\Component\Console\Helper\TableCell;
24
use Symfony\Component\Console\Helper\TableSeparator;
25
use Symfony\Component\Console\Helper\TableStyle;
26
use Symfony\Component\Console\Input\InputDefinition;
27
use Symfony\Component\Console\Input\InputInterface;
28
use Symfony\Component\Console\Input\InputOption;
29
use Symfony\Component\Console\Output\OutputInterface;
30
31
class ScanCommand extends Command
32
{
33
    /** @var VideoInfoReaderInterface */
34
    private $reader;
35
36
    /** @var string[] */
37
    private $supportedVideoExtensions = [
38
        'mov',
39
        'mp4',
40
        'm4v',
41
        'mkv',
42
        'flv',
43
        'webm',
44
    ];
45
46 4
    public function __construct(VideoInfoReaderInterface $videoInfoReader)
47
    {
48 4
        $this->reader = $videoInfoReader;
49 4
        parent::__construct();
50 4
    }
51
52
    /**
53
     * Configures the command.
54
     */
55 4
    protected function configure(): void
56
    {
57
        $this
58 4
            ->setName('scan:videos')
59 4
            ->setDescription('Scan for video')
60 4
            ->setDefinition(
61 4
                new InputDefinition([
62 4
                    new InputOption('dir', 'd', InputOption::VALUE_REQUIRED),
63
                ])
64
            );
65 4
    }
66
67 4
    protected function execute(InputInterface $input, OutputInterface $output): int
68
    {
69 4
        if (!$input->hasOption('dir')) {
70
            throw new \InvalidArgumentException('Missing dir argument, use <command> <dir>');
71
        }
72 4
        $videoPath = $input->hasOption('dir') ? $input->getOption('dir') : null;
73 4
        if (!is_string($videoPath) || !is_dir($videoPath)) {
74 2
            throw new \InvalidArgumentException(sprintf(
75 2
                'Video dir %s does not exists',
76 2
                is_string($videoPath) ? $videoPath : json_encode($videoPath)
77
            ));
78
        }
79
80 2
        $output->writeln(sprintf('* Scanning %s for files...', $videoPath));
81
82
        // Get the videos in path
83 2
        $videos = (new DirectoryScanner())->findFiles($videoPath, $this->supportedVideoExtensions);
84
85 2
        $output->writeln('* Reading metadata...');
86
87 2
        $progressBar = new ProgressBar($output, count($videos));
88 2
        $progressBar->start();
89
90 2
        $bitRateFormatter = new ByteFormatter();
91 2
        $sizeFormatter    = new ByteFormatter();
92
93 2
        $rows      = [];
94 2
        $warnings  = [];
95 2
        $totalSize = 0;
96
97
        /** @var \SplFileInfo $video */
98 2
        foreach ($videos as $video) {
99 2
            $videoFile = $video->getPathname();
100
            try {
101 2
                $info     = $this->reader->getInfo($videoFile);
102 1
                $vStream  = $info->getVideoStreams()->getFirst();
103 1
                $aStream  = $info->getAudioStreams()->getFirst();
104 1
                $pixFmt   = $vStream->getPixFmt();
105 1
                $bitRate  = $vStream->getBitRate();
106 1
                $fileSize = $video->getSize();
107
108 1
                $fps             = $vStream->getRFrameRate() ?? '';
109 1
                [$frames, $base] = explode('/', $fps);
110
111 1
                $fps2 = number_format($frames / $base, 3, '.', '');
112
113
                try {
114 1
                    $fps3 = number_format($vStream->getNbFrames() ?? 0 / $vStream->getDuration() ?? 1, 3, '.', '');
115
                } catch (\Throwable $e) {
116
                    $fps3 = '?';
117
                }
118
                //$fps2 = $vStream->getNbFrames() > 0 ? $vStream->getNbFrames() / $vStream->getDurationTs() : null;
119
120
                $row = [
121 1
                    $video,
122 1
                    preg_replace('/\.([0-9])+$/', '', SeekTime::convertSecondsToHMSs(round($info->getDuration(), 1))),
123 1
                    sprintf('%s/%s', $vStream->getCodecName(), $aStream->getCodecName()),
124 1
                    sprintf('%sx%s', $vStream->getWidth(), $vStream->getHeight()),
125 1
                    ($bitRate > 0 ? $bitRateFormatter->format((int) $bitRate) . '/s' : ''),
126 1
                    $fps . ' - ' . $fps2 . ' - ' . $fps3,
127 1
                    $sizeFormatter->format($fileSize),
128 1
                    $pixFmt,
129
                ];
130 1
                $rows[] = $row;
131 1
                $totalSize += $fileSize;
132 2
            } catch (VideoException\MissingFFProbeBinaryException $e) {
133 1
                throw new MissingFFProbeBinaryException('Unable to run ffprobe binary, check your config and ensure it\'s properly installed');
134 1
            } catch (VideoException\InfoReaderExceptionInterface $e) {
135 1
                $warnings[] = [$videoFile];
136
            }
137
138 1
            $progressBar->advance();
139
        }
140 1
        $progressBar->finish();
141
142 1
        $output->writeln('');
143 1
        $output->writeln('* Available media files:');
144
145 1
        $this->renderResultsTable($output, $rows, $totalSize);
146
147
        // display warnings
148 1
        if (count($warnings) > 0) {
149 1
            $output->writeln('* The following files were not detected as valid medias:');
150 1
            $table = new Table($output);
151 1
            $table->setHeaders([
152 1
                'Unsupported files',
153
            ]);
154 1
            $table->setStyle('box-double');
155 1
            $table->setRows($warnings);
156 1
            $table->render();
157
        }
158
159 1
        $output->writeln('');
160
161 1
        return 0;
162
    }
163
164 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

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