Passed
Push — master ( 7f9bd8...8d36fd )
by Sébastien
02:37
created

ScanCommand::execute()   F

Complexity

Conditions 15
Paths 373

Size

Total Lines 119
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 70
CRAP Score 15.0048

Importance

Changes 0
Metric Value
cc 15
eloc 79
nc 373
nop 2
dl 0
loc 119
ccs 70
cts 72
cp 0.9722
crap 15.0048
rs 2.7948
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\Video\Exception as VideoException;
17
use Soluble\MediaTools\Video\SeekTime;
18
use Soluble\MediaTools\Video\VideoInfoReaderInterface;
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Helper\ProgressBar;
21
use Symfony\Component\Console\Helper\Table;
22
use Symfony\Component\Console\Helper\TableCell;
23
use Symfony\Component\Console\Helper\TableSeparator;
24
use Symfony\Component\Console\Helper\TableStyle;
25
use Symfony\Component\Console\Input\InputDefinition;
26
use Symfony\Component\Console\Input\InputInterface;
27
use Symfony\Component\Console\Input\InputOption;
28
use Symfony\Component\Console\Output\OutputInterface;
29
use Symfony\Component\Finder\Finder;
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 3
    public function __construct(VideoInfoReaderInterface $videoInfoReader)
47
    {
48 3
        $this->reader = $videoInfoReader;
49 3
        parent::__construct();
50 3
    }
51
52
    /**
53
     * Configures the command.
54
     */
55 3
    protected function configure(): void
56
    {
57
        $this
58 3
            ->setName('scan:videos')
59 3
            ->setDescription('Scan for video')
60 3
            ->setDefinition(
61 3
                new InputDefinition([
62 3
                    new InputOption('dir', 'd', InputOption::VALUE_REQUIRED),
63
                ])
64
            );
65 3
    }
66
67 3
    protected function execute(InputInterface $input, OutputInterface $output): int
68
    {
69 3
        if (!$input->hasOption('dir')) {
70
            throw new \InvalidArgumentException('Missing dir argument, use <command> <dir>');
71
        }
72 3
        $videoPath = $input->hasOption('dir') ? $input->getOption('dir') : null;
73 3
        if (!is_string($videoPath) || !is_dir($videoPath)) {
74 1
            throw new \InvalidArgumentException(sprintf(
75 1
                'Video dir %s does not exists',
76 1
                is_string($videoPath) ? $videoPath : json_encode($videoPath)
77
            ));
78
        }
79
80 2
        $output->writeln(sprintf('Scanning %s', $videoPath));
81
82
        // Get the videos in path
83 2
        $videos = $this->getVideoFiles($videoPath);
84
85 2
        $progressBar = new ProgressBar($output, count($videos));
86 2
        $progressBar->start();
87
88 2
        $bitRateFormatter = new ByteFormatter();
89
        //$bitRateFormatter->setUnitDecorator(new SymbolDecorator(SymbolDecorator::SUFFIX_NONE));
90
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
                $pixFmt   = $vStream->getPixFmt();
104 1
                $bitRate  = $vStream->getBitRate();
105 1
                $fileSize = (int) filesize($videoFile);
106
                $row      = [
107 1
                    $video,
108 1
                    preg_replace('/\.([0-9])+$/', '', SeekTime::convertSecondsToHMSs(round($info->getDuration(), 1))),
109 1
                    $vStream->getCodecName(),
110 1
                    sprintf('%sx%s', $vStream->getWidth(), $vStream->getHeight()),
111 1
                    ($bitRate > 0 ? $bitRateFormatter->format((int) $bitRate) . '/s' : ''),
112 1
                    $sizeFormatter->format($fileSize),
113 1
                    $pixFmt,
114
                ];
115 1
                $rows[] = $row;
116 1
                $totalSize += $fileSize;
117 2
            } catch (VideoException\MissingFFProbeBinaryException $e) {
118 1
                throw new MissingFFProbeBinaryException('Unable to run ffprobe binary, check your config and ensure it\'s properly installed');
119 1
            } catch (VideoException\InfoReaderExceptionInterface $e) {
120 1
                $warnings[] = [$videoFile];
121
            }
122
123 1
            $progressBar->advance();
124
        }
125
126 1
        $output->writeln('');
127
128 1
        $table = new Table($output);
129
130 1
        $rightAlignstyle = new TableStyle();
131 1
        $rightAlignstyle->setPadType(STR_PAD_LEFT);
132
133
        //$table->setStyle($tableStyle);
134 1
        $table->setStyle('box');
135 1
        $table->setHeaders([
136 1
            'file',
137
            'duration',
138
            'codec',
139
            'size',
140
            'bitrate',
141
            'filesize',
142
            'pix_fmt',
143
        ]);
144
145 1
        $previousPath = null;
146 1
        $first        = true;
147
148 1
        foreach ($rows as $row) {
149
            /** @var \SplFileInfo $file */
150 1
            $file   = $row[0];
151 1
            $row[0] = $file->getBasename();
152 1
            if ($previousPath !== $file->getPath()) {
153 1
                if (!$first) {
154
                    $table->addRow(new TableSeparator(['colspan' => count($row)]));
155
                }
156
                //$table->addRow([new TableCell(sprintf('<fg=yellow>%s</>', $file->getPath()), ['colspan' => count($row)])]);
157 1
                $table->addRow([new TableCell(sprintf('<fg=yellow>%s</>', $file->getPath()))]);
158 1
                $table->addRow(new TableSeparator(['colspan' => count($row)]));
159 1
                $previousPath = $file->getPath();
160
            }
161 1
            $table->addRow($row);
162 1
            $first = false;
163
        }
164 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...
165 1
            $table->setColumnStyle($idx, $rightAlignstyle);
166
        }
167 1
        $table->addRow(new TableSeparator());
168 1
        $table->addRow(['<fg=cyan>Total</>', '', '', '', '', sprintf('<fg=cyan>%s</>', $sizeFormatter->format($totalSize))]);
169
170 1
        $table->render();
171
172
        // display warnings
173 1
        if (count($warnings) > 0) {
174 1
            $table = new Table($output);
175 1
            $table->setHeaders([
176 1
                'Unsupported files',
177
            ]);
178 1
            $table->setStyle('box');
179 1
            $table->setRows($warnings);
180 1
            $table->render();
181
        }
182
183 1
        $output->writeln("\nFinished");
184
185 1
        return 0;
186
    }
187
188
    private function outputTable(array $rows): void
0 ignored issues
show
Unused Code introduced by
The method outputTable() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
Unused Code introduced by
The parameter $rows 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

188
    private function outputTable(/** @scrutinizer ignore-unused */ array $rows): 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...
189
    {
190
    }
191
192
    /**
193
     * @param string $videoPath
194
     *
195
     * @return array<\SplFileInfo>
196
     */
197 2
    public function getVideoFiles(string $videoPath): array
198
    {
199 2
        $files = (new Finder())->files()
200 2
            ->in($videoPath)
201 2
            ->ignoreUnreadableDirs()
202 2
            ->name(sprintf(
203 2
                '/\.(%s)$/',
204 2
                implode('|', $this->supportedVideoExtensions)
205
            ));
206
207 2
        $videos = [];
208
209
        /** @var \SplFileInfo $file */
210 2
        foreach ($files as $file) {
211 2
            $videos[] = $file;
212
        }
213
214 2
        return $videos;
215
    }
216
}
217