Passed
Push — master ( c491f6...ec8dab )
by Sébastien
02:19
created

ScanCommand::execute()   F

Complexity

Conditions 14
Paths 355

Size

Total Lines 117
Code Lines 77

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 210

Importance

Changes 0
Metric Value
cc 14
eloc 77
nc 355
nop 2
dl 0
loc 117
ccs 0
cts 92
cp 0
crap 210
rs 3.2984
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
namespace Soluble\MediaTools\Cli\Command;
6
7
use ScriptFUSION\Byte\ByteFormatter;
8
use ScriptFUSION\Byte\Unit\SymbolDecorator;
9
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
10
use Soluble\MediaTools\Video\SeekTime;
11
use Soluble\MediaTools\Video\VideoInfoReaderInterface;
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Helper\ProgressBar;
14
use Symfony\Component\Console\Helper\Table;
15
use Symfony\Component\Console\Helper\TableCell;
16
use Symfony\Component\Console\Helper\TableSeparator;
17
use Symfony\Component\Console\Helper\TableStyle;
18
use Symfony\Component\Console\Input\InputDefinition;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Finder\Finder;
23
24
class ScanCommand extends Command
25
{
26
    /**
27
     * @var VideoInfoReaderInterface
28
     */
29
    private $reader;
30
31
    /** @var string[] */
32
    private $supportedVideoExtensions = [
33
        'mov',
34
        'mp4',
35
        'm4v',
36
        'mkv',
37
        'flv',
38
        'webm',
39
    ];
40
41
    public function __construct(VideoInfoReaderInterface $videoInfoReader)
42
    {
43
        $this->reader = $videoInfoReader;
44
        parent::__construct();
45
    }
46
47
    /**
48
     * Configures the command.
49
     */
50
    protected function configure(): void
51
    {
52
        $this
53
            ->setName('scan:videos')
54
            ->setDescription('Scan for video')
55
            ->setDefinition(
56
                new InputDefinition([
57
                    new InputOption('dir', 'd', InputOption::VALUE_REQUIRED),
58
                ])
59
            );
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    protected function execute(InputInterface $input, OutputInterface $output)
66
    {
67
        if (!$input->hasOption('dir')) {
68
            throw new \Exception('Missing dir argument, use <command> <dir>');
69
        }
70
        $videoPath = $input->hasOption('dir') ? $input->getOption('dir') : '';
71
        if (!is_string($videoPath) || !is_dir($videoPath)) {
72
            throw new \Exception(sprintf(
73
                'Video dir %s does not exists',
74
                is_string($videoPath) ? $videoPath : ''
75
            ));
76
        }
77
78
        $output->writeln(sprintf('Scanning %s', $videoPath));
79
80
        // Get the videos in path
81
        $videos = $this->getVideoFiles($videoPath);
82
83
        $progressBar = new ProgressBar($output, count($videos));
84
        $progressBar->start();
85
86
        $bitRateFormatter = new ByteFormatter();
87
        //$bitRateFormatter->setUnitDecorator(new SymbolDecorator(SymbolDecorator::SUFFIX_NONE));
88
89
        $sizeFormatter = new ByteFormatter();
90
91
        $rows      = [];
92
        $warnings  = [];
93
        $totalSize = 0;
94
95
        /** @var \SplFileInfo $video */
96
        foreach ($videos as $video) {
97
            $videoFile = $video->getPathname();
98
            try {
99
                $info     = $this->reader->getInfo($videoFile);
100
                $vStream  = $info->getVideoStreams()->getFirst();
101
                $pixFmt   = $vStream->getPixFmt();
102
                $bitRate  = $vStream->getBitRate();
103
                $fileSize = (int) filesize($videoFile);
104
                $row      = [
105
                    $video,
106
                    preg_replace('/\.([0-9])+$/', '', SeekTime::convertSecondsToHMSs(round($info->getDuration(), 1))),
107
                    $vStream->getCodecName(),
108
                    sprintf('%sx%s', $vStream->getWidth(), $vStream->getHeight()),
109
                    ($bitRate > 0 ? $bitRateFormatter->format((int) $bitRate) . '/s' : ''),
110
                    $sizeFormatter->format($fileSize),
111
                    $pixFmt,
112
                ];
113
                $rows[] = $row;
114
                $totalSize += $fileSize;
115
            } catch (InfoReaderExceptionInterface $e) {
116
                $warnings[] = [$videoFile];
117
            }
118
119
            $progressBar->advance();
120
        }
121
122
        $output->writeln('');
123
124
        $table = new Table($output);
125
126
        $rightAlignstyle = new TableStyle();
127
        $rightAlignstyle->setPadType(STR_PAD_LEFT);
128
129
        //$table->setStyle($tableStyle);
130
        $table->setStyle('box');
131
        $table->setHeaders([
132
            'file',
133
            'duration',
134
            'codec',
135
            'size',
136
            'bitrate',
137
            'filesize',
138
            'pix_fmt',
139
        ]);
140
141
        $previousPath = null;
142
        $first        = true;
143
144
        foreach ($rows as $row) {
145
            /** @var \SplFileInfo $file */
146
            $file   = $row[0];
147
            $row[0] = $file->getBasename();
148
            if ($previousPath !== $file->getPath()) {
149
                if (!$first) {
150
                    $table->addRow(new TableSeparator(['colspan' => count($row)]));
151
                }
152
                //$table->addRow([new TableCell(sprintf('<fg=yellow>%s</>', $file->getPath()), ['colspan' => count($row)])]);
153
                $table->addRow([new TableCell(sprintf('<fg=yellow>%s</>', $file->getPath()))]);
154
                $table->addRow(new TableSeparator(['colspan' => count($row)]));
155
                $previousPath = $file->getPath();
156
            }
157
            $table->addRow($row);
158
            $first = false;
159
        }
160
        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...
161
            $table->setColumnStyle($idx, $rightAlignstyle);
162
        }
163
        $table->addRow(new TableSeparator());
164
        $table->addRow(['<fg=cyan>Total</>', '', '', '', '', sprintf('<fg=cyan>%s</>', $sizeFormatter->format($totalSize))]);
165
166
        $table->render();
167
168
        // display warnings
169
        if (count($warnings) > 0) {
170
            $table = new Table($output);
171
            $table->setHeaders([
172
                'Unsupported files'
173
            ]);
174
            $table->setStyle('box');
175
            $table->setRows($warnings);
176
            $table->render();
177
        }
178
179
        $output->writeln("\nFinished");
180
181
        return 1;
182
    }
183
184
    private function outputTable(array $rows): void
0 ignored issues
show
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

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