GenerateVideoCoversCommand::makeCover()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 9
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 16
ccs 0
cts 14
cp 0
crap 12
rs 9.9666
1
<?php
2
3
declare(strict_types=1);
4
5
namespace App\Command;
6
7
use Soluble\MediaTools\Video\Filter\NlmeansVideoFilter;
8
use Soluble\MediaTools\Video\SeekTime;
9
use Soluble\MediaTools\Video\VideoInfoReaderInterface;
10
use Soluble\MediaTools\Video\VideoThumbGeneratorInterface;
11
use Soluble\MediaTools\Video\VideoThumbParams;
12
use Symfony\Component\Console\Command\Command;
13
use Symfony\Component\Console\Input\InputDefinition;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Finder\Finder;
18
19
class GenerateVideoCoversCommand extends Command
20
{
21
    /**
22
     * @var VideoThumbGeneratorInterface
23
     */
24
    protected $thumbGenerator;
25
26
    /**
27
     * @var VideoInfoReaderInterface
28
     */
29
    protected $infoReader;
30
31
    /**
32
     * @var array<string>
33
     */
34
    protected $supportedVideoExtensions = [
35
        'webm', 'mov', 'mkv'
36
    ];
37
38
    public function __construct(VideoThumbGeneratorInterface $thumbGenerator, VideoInfoReaderInterface $infoReader)
39
    {
40
        $this->thumbGenerator = $thumbGenerator;
41
        $this->infoReader     = $infoReader;
42
        parent::__construct();
43
    }
44
45
    /**
46
     * Configures the command.
47
     */
48
    protected function configure(): void
49
    {
50
        $this
51
            ->setName('generate:video:covers')
52
            ->setDescription('Generate video covers from input directory')
53
            ->setDefinition(
54
                new InputDefinition([
55
                    new InputOption('dir', 'd', InputOption::VALUE_REQUIRED),
56
                ])
57
            );
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    protected function execute(InputInterface $input, OutputInterface $output)
64
    {
65
        if (!$input->hasOption('dir')) {
66
            throw new \Exception('Missing dir argument, use <command> <dir>');
67
        }
68
        $videoPath = $input->hasOption('dir') ? $input->getOption('dir') : '';
69
        if (!is_string($videoPath) || !is_dir($videoPath)) {
70
            throw new \Exception(sprintf(
71
                'Video dir %s does not exists',
72
                is_string($videoPath) ? $videoPath : ''
73
            ));
74
        }
75
76
        $output->writeln('Processing covers...');
77
        $output->writeln('');
78
79
        $extraCoversPath = $videoPath . '/covers';
80
        if (!is_dir($extraCoversPath)) {
81
            $ret = mkdir($extraCoversPath);
82
            if ($ret === false) {
83
                throw new \Exception(sprintf(
84
                    'Cannot create directory %s',
85
                    $extraCoversPath
86
                ));
87
            }
88
        }
89
90
        $videos = $this->getVideoFiles($videoPath);
91
92
        $format = 'jpg';
93
94
        foreach ($videos as $video) {
95
            // Make single cover
96
            $this->makeCover(
97
                $video,
98
                sprintf(
99
                    '%s/%s.%s',
100
                    $extraCoversPath, //dirname($video),
101
                    basename($video, '.' . pathinfo($video, PATHINFO_EXTENSION)),
102
                    $format
103
                ),
104
                new SeekTime(1.0)
105
            );
106
107
            $this->makeCovers($video, $extraCoversPath, $format, 5);
108
109
            $output->writeln($video);
110
        }
111
112
        $output->writeln("\nFinished");
113
114
        return 1;
115
    }
116
117
    public function makeCover(string $videoFile, string $outputFile, ?SeekTime $seekTime = null): void
118
    {
119
        if ($seekTime !== null) {
120
            $videoInfo = $this->infoReader->getInfo($videoFile);
121
122
            if ($seekTime->getTime() > $videoInfo->getDuration()) {
123
                $seekTime = new SeekTime($videoInfo->getDuration());
124
            }
125
        } else {
126
            $seekTime = new SeekTime(0.0);
127
        }
128
        $thumbParams = (new VideoThumbParams())->withSeekTime($seekTime)->withVideoFilter(
129
            new NlmeansVideoFilter()
130
        );
131
132
        $this->thumbGenerator->makeThumbnail($videoFile, $outputFile, $thumbParams);
133
    }
134
135
    public function makeCovers(string $videoFile, string $outputPath, string $format, int $numberOfThumbs): void
136
    {
137
        $videoInfo = $this->infoReader->getInfo($videoFile);
138
        $duration  = $videoInfo->getDuration();
139
140
        $videoBaseName = basename($videoFile, '.' . pathinfo($videoFile, PATHINFO_EXTENSION));
141
142
        for ($i = 0; $i < $numberOfThumbs; ++$i) {
143
            $outputFile = sprintf(
144
                '%s/%s-%02d.%s',
145
                $outputPath,
146
                $videoBaseName,
147
                $i + 1,
148
                $format
149
            );
150
151
            $time = ceil($duration / $numberOfThumbs * $i);
152
153
            $thumbParams = (new VideoThumbParams())
154
                ->withVideoFilter(
155
                    new NlmeansVideoFilter()
156
                )
157
                ->withSeekTime(new SeekTime($time));
158
159
            $this->thumbGenerator->makeThumbnail($videoFile, $outputFile, $thumbParams);
160
        }
161
    }
162
163
    /**
164
     * @param string $videoPath
165
     *
166
     * @return string[]
167
     */
168
    public function getVideoFiles(string $videoPath): array
169
    {
170
        $files = (new Finder())->files()
171
            ->in($videoPath)
172
            ->name(sprintf(
173
                '/\.(%s)$/',
174
                implode('|', $this->supportedVideoExtensions)
175
            ));
176
177
        $videos = [];
178
179
        /** @var \SplFileInfo $file */
180
        foreach ($files as $file) {
181
            $videos[] = $file->getPathname();
182
        }
183
184
        return $videos;
185
    }
186
}
187