AzuraCast/src/Entity/Repository/PodcastMediaRepository.php

97 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Entity\Repository;
use App\Doctrine\ReloadableEntityManagerInterface;
use App\Doctrine\Repository;
use App\Entity\PodcastEpisode;
use App\Entity\PodcastMedia;
use App\Environment;
use App\Exception\InvalidPodcastMediaFileException;
use App\Media\MetadataService\GetId3MetadataService;
use Azura\Files\ExtendedFilesystemInterface;
use Intervention\Image\ImageManager;
use League\Flysystem\UnableToDeleteFile;
use Psr\Log\LoggerInterface;
use Symfony\Component\Serializer\Serializer;
class PodcastMediaRepository extends Repository
{
public function __construct(
ReloadableEntityManagerInterface $em,
Serializer $serializer,
Environment $environment,
LoggerInterface $logger,
protected GetId3MetadataService $metadataService,
protected ImageManager $imageManager
) {
parent::__construct($em, $serializer, $environment, $logger);
}
public function upload(
PodcastEpisode $episode,
string $originalPath,
string $uploadPath,
?ExtendedFilesystemInterface $fs = null
): ?string {
$podcast = $episode->getPodcast();
$storageLocation = $podcast->getStorageLocation();
$fs ??= $storageLocation->getFilesystem();
// Do an early metadata check of the new media to avoid replacing a valid file with an invalid one.
$metadata = $this->metadataService->readMetadata($uploadPath);
if (!in_array($metadata->getMimeType(), ['audio/x-m4a', 'audio/mpeg'])) {
throw new InvalidPodcastMediaFileException(
'Invalid Podcast Media mime type: ' . $metadata->getMimeType()
);
}
if ($episode->getMedia() instanceof PodcastMedia) {
$this->delete($episode->getMedia(), $fs);
$episode->setMedia(null);
}
$ext = pathinfo($originalPath, PATHINFO_EXTENSION);
$path = $podcast->getId() . '/' . $episode->getId() . '.' . $ext;
$podcastMedia = new PodcastMedia($storageLocation);
$podcastMedia->setPath($path);
$podcastMedia->setOriginalName(basename($originalPath));
// Load metadata from local file while it's available.
$podcastMedia->setLength($metadata->getDuration());
$podcastMedia->setMimeType($metadata->getMimeType());
// Upload local file remotely.
$fs->uploadAndDeleteOriginal($uploadPath, $path);
$podcastMedia->setEpisode($episode);
$this->em->persist($podcastMedia);
$episode->setMedia($podcastMedia);
$this->em->persist($episode);
$this->em->flush();
return $metadata->getArtwork();
}
public function delete(
PodcastMedia $media,
?ExtendedFilesystemInterface $fs = null
): void {
$fs ??= $media->getStorageLocation()->getFilesystem();
try {
$fs->delete($media->getPath());
} catch (UnableToDeleteFile) {
}
$this->em->remove($media);
$this->em->flush();
}
}