Daniel Siepmann
8124631d5d
Some systems might have limited temp folder sizes. A new option is added to configure the folder to use for temp files.
169 lines
5.1 KiB
PHP
169 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace DanielSiepmann\Videcutting;
|
|
|
|
/*
|
|
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
use Symfony\Component\Process\Process;
|
|
|
|
class Cutting
|
|
{
|
|
/**
|
|
* @var VideoInfo
|
|
*/
|
|
private $video;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $tempFolder = '';
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
private $tempFilenames = [];
|
|
|
|
public function __construct(
|
|
VideoInfo $video,
|
|
?string $tempFolder = null
|
|
) {
|
|
$this->video = $video;
|
|
$this->tempFolder = $tempFolder ?? sys_get_temp_dir();
|
|
}
|
|
|
|
public function getCommandsForCutting(): \Generator
|
|
{
|
|
$start = $this->video->getStart();
|
|
$end = $this->video->getEnd();
|
|
|
|
if ($this->video->getAds() === []) {
|
|
yield $this->getCuttingCommand($start, $end);
|
|
return;
|
|
}
|
|
|
|
// Each video starts with end of last ad, and end at next ad start.
|
|
foreach ($this->video->getAds() as [$adStart, $adEnd]) {
|
|
$end = $adStart;
|
|
|
|
yield $this->getCuttingCommand($start, $end);
|
|
|
|
$start = $adEnd;
|
|
}
|
|
|
|
yield $this->getCuttingCommand($start, $this->video->getEnd());
|
|
}
|
|
|
|
public function getCommandForGeneratingMetadata(): Process
|
|
{
|
|
$command = sprintf(
|
|
'ffmpeg -y -i %s -f ffmetadata %s',
|
|
escapeshellarg($this->video->getOriginalFilename()),
|
|
escapeshellarg($this->getMetadataFilename())
|
|
);
|
|
|
|
return Process::fromShellCommandline($command);
|
|
}
|
|
|
|
public function getCommandForGeneratingConcatInputFile(): Process
|
|
{
|
|
if ($this->tempFilenames === []) {
|
|
throw new \InvalidArgumentException(
|
|
'No temp files for concat available. Did you call "getCommandsForCutting()" before?',
|
|
1601455216
|
|
);
|
|
}
|
|
|
|
$lines = [];
|
|
foreach ($this->tempFilenames as $filename) {
|
|
$lines[] = 'file ' . $filename;
|
|
}
|
|
|
|
$command = 'printf ' . escapeshellarg(implode('\n', $lines)) . ' > ' . $this->getConcatFilename();
|
|
return Process::fromShellCommandline($command);
|
|
}
|
|
|
|
public function getCommandForGeneratingVideo(): Process
|
|
{
|
|
$command = sprintf(
|
|
'ffmpeg -y -f concat -safe 0 -i %s -c copy'
|
|
. ' -f ffmetadata -i %s -c copy -map_metadata 1'
|
|
. ' -metadata Title=' . escapeshellarg($this->video->getTitleForHumans())
|
|
. ' %s',
|
|
escapeshellarg($this->getConcatFilename()),
|
|
escapeshellarg($this->getMetadataFilename()),
|
|
escapeshellarg($this->video->getTargetFilePath())
|
|
);
|
|
return Process::fromShellCommandline($command);
|
|
}
|
|
|
|
public function getCommandForCleanup(): Process
|
|
{
|
|
$tempfiles = implode(' ', array_map(function (string $filename) {
|
|
return escapeshellarg($filename);
|
|
}, $this->tempFilenames));
|
|
|
|
$command = sprintf(
|
|
'rm %s %s %s',
|
|
$tempfiles,
|
|
escapeshellarg($this->getConcatFilename()),
|
|
escapeshellarg($this->getMetadataFilename())
|
|
);
|
|
return Process::fromShellCommandline($command);
|
|
}
|
|
|
|
private function getCuttingCommand(string $start, string $end): Process
|
|
{
|
|
$command = sprintf(
|
|
'ffmpeg -y -ss %s -to %s -i %s -c copy %s',
|
|
escapeshellarg($start),
|
|
escapeshellarg($end),
|
|
escapeshellarg($this->video->getOriginalFilename()),
|
|
escapeshellarg($this->getNextTempFilename())
|
|
);
|
|
|
|
return Process::fromShellCommandline($command);
|
|
}
|
|
|
|
private function getNextTempFilename(): string
|
|
{
|
|
$count = count($this->tempFilenames) + 1;
|
|
$nextName = $this->tempFolder
|
|
. DIRECTORY_SEPARATOR
|
|
. $this->video->getOriginalFilenameWithSuffix('cut-' . $count);
|
|
|
|
$this->tempFilenames[] = $nextName;
|
|
return $nextName;
|
|
}
|
|
|
|
private function getMetadataFilename(): string
|
|
{
|
|
$file = new \SplFileInfo($this->video->getOriginalFilenameWithSuffix('metadata'));
|
|
|
|
return $this->tempFolder . DIRECTORY_SEPARATOR . $file->getBasename('.' . $file->getExtension()) . '.txt';
|
|
}
|
|
|
|
private function getConcatFilename(): string
|
|
{
|
|
$file = new \SplFileInfo($this->video->getOriginalFilenameWithSuffix('concat'));
|
|
|
|
return $this->tempFolder . DIRECTORY_SEPARATOR . $file->getBasename('.' . $file->getExtension()) . '.txt';
|
|
}
|
|
}
|