Passed
Push — master ( df600e...bfce09 )
by Sébastien
05:12
created

ScanCommand::execute()   C

Complexity

Conditions 12
Paths 77

Size

Total Lines 89
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 58
CRAP Score 12.0006

Importance

Changes 0
Metric Value
cc 12
eloc 60
nc 77
nop 2
dl 0
loc 89
ccs 58
cts 59
cp 0.9831
crap 12.0006
rs 6.446
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 = (string) ($vStream->getFps(0) ?? '');
109
110
                $row = [
111 1
                    'video'      => $video,
112 1
                    'duration'   => preg_replace('/\.([0-9])+$/', '', SeekTime::convertSecondsToHMSs(round($info->getDuration(), 1))),
113 1
                    'codec'      => sprintf('%s/%s', $vStream->getCodecName(), $aStream->getCodecName()),
114 1
                    'resolution' => sprintf(
115 1
                        '%sx%s%s',
116 1
                        $vStream->getWidth(),
117 1
                        $vStream->getHeight(),
118 1
                        $fps !== '' ? " <fg=yellow>${fps}fps</>" : ''
119
                    ),
120 1
                    'bitrate' => ($bitRate > 0 ? $bitRateFormatter->format((int) $bitRate) . '/s' : ''),
121 1
                    'size'    => $sizeFormatter->format($fileSize),
122 1
                    'pixFmt'  => $pixFmt,
123
                ];
124 1
                $rows[] = $row;
125 1
                $totalSize += $fileSize;
126 2
            } catch (VideoException\MissingFFProbeBinaryException $e) {
127 1
                throw new MissingFFProbeBinaryException('Unable to run ffprobe binary, check your config and ensure it\'s properly installed');
128 1
            } catch (VideoException\InfoReaderExceptionInterface $e) {
129 1
                $warnings[] = [$videoFile];
130
            }
131
132 1
            $progressBar->advance();
133
        }
134 1
        $progressBar->finish();
135
136 1
        $output->writeln('');
137 1
        $output->writeln('* Available media files:');
138
139 1
        $this->renderResultsTable($output, $rows, $totalSize);
140
141
        // display warnings
142 1
        if (count($warnings) > 0) {
143 1
            $output->writeln('* The following files were not detected as valid medias:');
144 1
            $table = new Table($output);
145 1
            $table->setHeaders([
146 1
                'Unsupported files',
147
            ]);
148 1
            $table->setStyle('box-double');
149 1
            $table->setRows($warnings);
150 1
            $table->render();
151
        }
152
153 1
        $output->writeln('');
154
155 1
        return 0;
156
    }
157
158 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

158
    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...
159
    {
160 1
        $sizeFormatter = new ByteFormatter();
161
162 1
        $table = new Table($output);
163
164 1
        $rightAlignstyle = new TableStyle();
165 1
        $rightAlignstyle->setPadType(STR_PAD_LEFT);
166
167
        //$table->setStyle($tableStyle);
168 1
        $table->setStyle('box');
169 1
        $table->setHeaders([
170 1
            'file',
171
            'duration',
172
            'codec',
173
            'size',
174
            'bitrate',
175
            'filesize',
176
            'pix_fmt',
177
        ]);
178
179 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...
180 1
            $table->setColumnStyle($idx, $rightAlignstyle);
181
        }
182
183 1
        $previousPath = null;
184 1
        $first        = true;
185
186 1
        foreach ($rows as $idx => $row) {
187
            /** @var \SplFileInfo $file */
188 1
            $file         = $row['video'];
189 1
            $fileName     = $file->getBasename();
190 1
            $fileName     = mb_strlen($fileName) > 30 ? mb_substr($file->getBasename(), 0, 30) . '[...].' . $file->getExtension() : $fileName;
191 1
            $row['video'] = $fileName;
192 1
            if ($previousPath !== $file->getPath()) {
193 1
                if (!$first) {
194
                    $table->addRow(new TableSeparator(['colspan' => count($row)]));
195
                }
196 1
                $table->addRow([new TableCell(sprintf('<fg=yellow>%s</>', $file->getPath()), ['colspan' => count($row)])]);
197 1
                $table->addRow(new TableSeparator(['colspan' => count($row)]));
198 1
                $previousPath = $file->getPath();
199
            }
200 1
            $table->addRow($row);
201 1
            $first = false;
202
        }
203
204 1
        $table->addRow(new TableSeparator());
205 1
        $table->addRow(['<fg=cyan>Total</>', '', '', '', '', sprintf('<fg=cyan>%s</>', $sizeFormatter->format($totalSize))]);
206
207 1
        $table->render();
208 1
    }
209
}
210