Completed
Push — master ( 18000e...919955 )
by Sébastien
02:06
created

ScanCommand::getVideoFiles()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 1
dl 0
loc 18
ccs 11
cts 11
cp 1
crap 2
rs 9.9332
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
 * @copyright Copyright (c) 2018-2019 Sébastien Vanvelthem. (https://github.com/belgattitude)
8
 * @license   https://github.com/soluble-io/soluble-mediatools-cli/blob/master/LICENSE.md MIT
9
 */
10
11
namespace Soluble\MediaTools\Cli\Command;
12
13
use ScriptFUSION\Byte\ByteFormatter;
14
use Soluble\MediaTools\Video\Exception\InfoReaderExceptionInterface;
15
use Soluble\MediaTools\Video\SeekTime;
16
use Soluble\MediaTools\Video\VideoInfoReaderInterface;
17
use Symfony\Component\Console\Command\Command;
18
use Symfony\Component\Console\Helper\ProgressBar;
19
use Symfony\Component\Console\Helper\Table;
20
use Symfony\Component\Console\Helper\TableCell;
21
use Symfony\Component\Console\Helper\TableSeparator;
22
use Symfony\Component\Console\Helper\TableStyle;
23
use Symfony\Component\Console\Input\InputDefinition;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Console\Output\OutputInterface;
27
use Symfony\Component\Finder\Finder;
28
29
class ScanCommand extends Command
30
{
31
    /** @var VideoInfoReaderInterface */
32
    private $reader;
33
34
    /** @var string[] */
35
    private $supportedVideoExtensions = [
36
        'mov',
37
        'mp4',
38
        'm4v',
39
        'mkv',
40
        'flv',
41
        'webm',
42
    ];
43
44 2
    public function __construct(VideoInfoReaderInterface $videoInfoReader)
45
    {
46 2
        $this->reader = $videoInfoReader;
47 2
        parent::__construct();
48 2
    }
49
50
    /**
51
     * Configures the command.
52
     */
53 2
    protected function configure(): void
54
    {
55
        $this
56 2
            ->setName('scan:videos')
57 2
            ->setDescription('Scan for video')
58 2
            ->setDefinition(
59 2
                new InputDefinition([
60 2
                    new InputOption('dir', 'd', InputOption::VALUE_REQUIRED),
61
                ])
62
            );
63 2
    }
64
65 2
    protected function execute(InputInterface $input, OutputInterface $output): int
66
    {
67 2
        if (!$input->hasOption('dir')) {
68
            throw new \InvalidArgumentException('Missing dir argument, use <command> <dir>');
69
        }
70 2
        $videoPath = $input->hasOption('dir') ? $input->getOption('dir') : null;
71 2
        if (!is_string($videoPath) || !is_dir($videoPath)) {
72 1
            throw new \InvalidArgumentException(sprintf(
73 1
                'Video dir %s does not exists',
74 1
                is_string($videoPath) ? $videoPath : json_encode($videoPath)
75
            ));
76
        }
77
78 1
        $output->writeln(sprintf('Scanning %s', $videoPath));
79
80
        // Get the videos in path
81 1
        $videos = $this->getVideoFiles($videoPath);
82
83 1
        $progressBar = new ProgressBar($output, count($videos));
84 1
        $progressBar->start();
85
86 1
        $bitRateFormatter = new ByteFormatter();
87
        //$bitRateFormatter->setUnitDecorator(new SymbolDecorator(SymbolDecorator::SUFFIX_NONE));
88
89 1
        $sizeFormatter = new ByteFormatter();
90
91 1
        $rows      = [];
92 1
        $warnings  = [];
93 1
        $totalSize = 0;
94
95
        /** @var \SplFileInfo $video */
96 1
        foreach ($videos as $video) {
97 1
            $videoFile = $video->getPathname();
98
            try {
99 1
                $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 1
            } catch (InfoReaderExceptionInterface $e) {
116 1
                $warnings[] = [$videoFile];
117
            }
118
119 1
            $progressBar->advance();
120
        }
121
122 1
        $output->writeln('');
123
124 1
        $table = new Table($output);
125
126 1
        $rightAlignstyle = new TableStyle();
127 1
        $rightAlignstyle->setPadType(STR_PAD_LEFT);
128
129
        //$table->setStyle($tableStyle);
130 1
        $table->setStyle('box');
131 1
        $table->setHeaders([
132 1
            'file',
133
            'duration',
134
            'codec',
135
            'size',
136
            'bitrate',
137
            'filesize',
138
            'pix_fmt',
139
        ]);
140
141 1
        $previousPath = null;
142 1
        $first        = true;
143
144 1
        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 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...
161 1
            $table->setColumnStyle($idx, $rightAlignstyle);
162
        }
163 1
        $table->addRow(new TableSeparator());
164 1
        $table->addRow(['<fg=cyan>Total</>', '', '', '', '', sprintf('<fg=cyan>%s</>', $sizeFormatter->format($totalSize))]);
165
166 1
        $table->render();
167
168
        // display warnings
169 1
        if (count($warnings) > 0) {
170 1
            $table = new Table($output);
171 1
            $table->setHeaders([
172 1
                'Unsupported files',
173
            ]);
174 1
            $table->setStyle('box');
175 1
            $table->setRows($warnings);
176 1
            $table->render();
177
        }
178
179 1
        $output->writeln("\nFinished");
180
181 1
        return 0;
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 1
    public function getVideoFiles(string $videoPath): array
194
    {
195 1
        $files = (new Finder())->files()
196 1
            ->in($videoPath)
197 1
            ->ignoreUnreadableDirs()
198 1
            ->name(sprintf(
199 1
                '/\.(%s)$/',
200 1
                implode('|', $this->supportedVideoExtensions)
201
            ));
202
203 1
        $videos = [];
204
205
        /** @var \SplFileInfo $file */
206 1
        foreach ($files as $file) {
207 1
            $videos[] = $file;
208
        }
209
210 1
        return $videos;
211
    }
212
}
213