#4050 -- Make each live DJ recording create a broadcast, not the other way around.
This commit is contained in:
parent
3d53b111f8
commit
617f06e278
|
@ -6,6 +6,7 @@ namespace App\Entity\Repository;
|
|||
|
||||
use App\Doctrine\Repository;
|
||||
use App\Entity;
|
||||
use Carbon\CarbonImmutable;
|
||||
|
||||
/**
|
||||
* @extends Repository<Entity\StationStreamerBroadcast>
|
||||
|
@ -65,8 +66,63 @@ class StationStreamerBroadcastRepository extends Repository
|
|||
public function findByPath(Entity\Station $station, string $path): ?Entity\StationStreamerBroadcast
|
||||
{
|
||||
return $this->repository->findOneBy([
|
||||
'station' => $station,
|
||||
'station' => $station,
|
||||
'recordingPath' => $path,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getOrCreateFromPath(
|
||||
Entity\Station $station,
|
||||
string $recordingPath,
|
||||
): ?Entity\StationStreamerBroadcast {
|
||||
$streamerUsername = pathinfo($recordingPath, PATHINFO_DIRNAME);
|
||||
|
||||
$streamer = $this->em->getRepository(Entity\StationStreamer::class)
|
||||
->findOneBy([
|
||||
'station' => $station,
|
||||
'streamer_username' => $streamerUsername,
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
if (null === $streamer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$startTimeRaw = str_replace(
|
||||
Entity\StationStreamerBroadcast::PATH_PREFIX . '_',
|
||||
'',
|
||||
pathinfo($recordingPath, PATHINFO_FILENAME)
|
||||
);
|
||||
$startTime = CarbonImmutable::createFromFormat(
|
||||
'Ymd-His',
|
||||
$startTimeRaw,
|
||||
$station->getTimezoneObject()
|
||||
);
|
||||
|
||||
if (false === $startTime) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$record = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT ssb
|
||||
FROM App\Entity\StationStreamerBroadcast ssb
|
||||
WHERE ssb.streamer = :streamer
|
||||
AND ssb.timestampStart >= :start AND ssb.timestampStart <= :end
|
||||
AND ssb.recordingPath IS NULL
|
||||
DQL
|
||||
)->setParameter('streamer', $streamer)
|
||||
->setParameter('start', $startTime->subMinute()->getTimestamp())
|
||||
->setParameter('end', $startTime->addMinute()->getTimestamp())
|
||||
->setMaxResults(1)
|
||||
->getOneOrNullResult();
|
||||
|
||||
if (null === $record) {
|
||||
$record = new Entity\StationStreamerBroadcast($streamer);
|
||||
}
|
||||
|
||||
$record->setTimestampStart($startTime->getTimestamp());
|
||||
$record->setRecordingPath($recordingPath);
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ use App\Doctrine\Repository;
|
|||
use App\Entity;
|
||||
use App\Environment;
|
||||
use App\Radio\AutoDJ\Scheduler;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
|
@ -82,21 +81,8 @@ class StationStreamerRepository extends Repository
|
|||
|
||||
$record = new Entity\StationStreamerBroadcast($streamer);
|
||||
$this->em->persist($record);
|
||||
|
||||
$backendConfig = $station->getBackendConfig();
|
||||
$recordStreams = $backendConfig->recordStreams();
|
||||
|
||||
if ($recordStreams) {
|
||||
$format = $backendConfig->getRecordStreamsFormatEnum() ?? StreamFormats::Mp3;
|
||||
$recordingPath = $record->generateRecordingPath($format);
|
||||
|
||||
$this->em->persist($record);
|
||||
$this->em->flush();
|
||||
|
||||
return $recordingPath;
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -115,7 +101,7 @@ class StationStreamerRepository extends Repository
|
|||
return true;
|
||||
}
|
||||
|
||||
protected function getStreamer(Entity\Station $station, string $username = ''): ?Entity\StationStreamer
|
||||
public function getStreamer(Entity\Station $station, string $username = ''): ?Entity\StationStreamer
|
||||
{
|
||||
/** @var Entity\StationStreamer|null $streamer */
|
||||
$streamer = $this->repository->findOneBy(
|
||||
|
|
|
@ -5,8 +5,6 @@ declare(strict_types=1);
|
|||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Interfaces\IdentifiableEntityInterface;
|
||||
use App\Radio\Enums\StreamFormats;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use OpenApi\Attributes as OA;
|
||||
|
||||
|
@ -69,6 +67,11 @@ class StationStreamerBroadcast implements IdentifiableEntityInterface
|
|||
return $this->timestampStart;
|
||||
}
|
||||
|
||||
public function setTimestampStart(int $timestampStart): void
|
||||
{
|
||||
$this->timestampStart = $timestampStart;
|
||||
}
|
||||
|
||||
public function getTimestampEnd(): int
|
||||
{
|
||||
return $this->timestampEnd;
|
||||
|
@ -84,17 +87,9 @@ class StationStreamerBroadcast implements IdentifiableEntityInterface
|
|||
return $this->recordingPath;
|
||||
}
|
||||
|
||||
public function generateRecordingPath(StreamFormats $format): string
|
||||
public function setRecordingPath(?string $recordingPath): void
|
||||
{
|
||||
$now = CarbonImmutable::createFromTimestamp(
|
||||
$this->timestampStart,
|
||||
$this->station->getTimezoneObject()
|
||||
);
|
||||
|
||||
$this->recordingPath = $this->streamer->getStreamerUsername()
|
||||
. '/' . self::PATH_PREFIX . '_' . $now->format('Ymd-His') . '.' . $format->getExtension();
|
||||
|
||||
return $this->recordingPath;
|
||||
$this->recordingPath = $recordingPath;
|
||||
}
|
||||
|
||||
public function clearRecordingPath(): void
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace App\Radio\Backend\Liquidsoap\Command;
|
||||
|
||||
use App\Entity;
|
||||
use App\Flysystem\StationFilesystems;
|
||||
use Monolog\Logger;
|
||||
|
||||
class DjOnCommand extends AbstractCommand
|
||||
|
@ -31,14 +30,6 @@ class DjOnCommand extends AbstractCommand
|
|||
]
|
||||
);
|
||||
|
||||
$resp = $this->streamerRepo->onConnect($station, $user);
|
||||
|
||||
if (is_string($resp)) {
|
||||
return (new StationFilesystems($station))
|
||||
->getTempFilesystem()
|
||||
->getLocalPath($resp);
|
||||
}
|
||||
|
||||
return $resp;
|
||||
return $this->streamerRepo->onConnect($station, $user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -714,8 +714,6 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
last_authenticated_dj = ref("")
|
||||
live_dj = ref("")
|
||||
|
||||
live_record_path = ref("")
|
||||
|
||||
def dj_auth(login) =
|
||||
auth_info =
|
||||
if (login.user == "source" or login.user == "") and (string.match(pattern="(:|,)+", login.password)) then
|
||||
|
@ -747,36 +745,22 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
live_enabled := true
|
||||
live_dj := dj
|
||||
|
||||
j = json()
|
||||
j.add("user", dj)
|
||||
|
||||
response = azuracast_api_call(
|
||||
_ = azuracast_api_call(
|
||||
timeout=5,
|
||||
"djon",
|
||||
json.stringify(j)
|
||||
json.stringify({user = dj})
|
||||
)
|
||||
if string.contains(prefix="/", response) then
|
||||
live_record_path := response
|
||||
end
|
||||
end
|
||||
|
||||
def live_disconnected() =
|
||||
dj = !live_dj
|
||||
|
||||
j = json()
|
||||
j.add("user", dj)
|
||||
|
||||
_ = azuracast_api_call(
|
||||
timeout=5,
|
||||
"djoff",
|
||||
json.stringify(j)
|
||||
json.stringify({user = !live_dj})
|
||||
)
|
||||
|
||||
live_enabled := false
|
||||
last_authenticated_dj := ""
|
||||
live_dj := ""
|
||||
|
||||
live_record_path := ""
|
||||
end
|
||||
EOF
|
||||
);
|
||||
|
@ -828,16 +812,21 @@ class ConfigWriter implements EventSubscriberInterface
|
|||
$recordLiveStreamsBitrate = (int)($settings['record_streams_bitrate'] ?? 128);
|
||||
|
||||
$formatString = $this->getOutputFormatString($recordLiveStreamsFormat, $recordLiveStreamsBitrate);
|
||||
$recordExtension = $recordLiveStreamsFormat->getExtension();
|
||||
$recordBasePath = self::cleanUpString($station->getRadioTempDir());
|
||||
$recordPathPrefix = Entity\StationStreamerBroadcast::PATH_PREFIX;
|
||||
|
||||
$event->appendBlock(
|
||||
<<< EOF
|
||||
# Record Live Broadcasts
|
||||
recording_base_path = "${recordBasePath}"
|
||||
recording_extension = "${recordExtension}"
|
||||
|
||||
output.file(
|
||||
{$formatString},
|
||||
fun () -> begin
|
||||
path = !live_record_path
|
||||
if (path != "") then
|
||||
"#{path}.tmp"
|
||||
if (!live_enabled) then
|
||||
"#{recording_base_path}/#{!live_dj}/${recordPathPrefix}_%Y%m%d-%H%M%S.#{recording_extension}.tmp"
|
||||
else
|
||||
""
|
||||
end
|
||||
|
|
|
@ -76,14 +76,21 @@ class MoveBroadcastsTask extends AbstractTask
|
|||
. 'Check temporary directory at path to recover file.',
|
||||
[
|
||||
'storageLocation' => (string)$storageLocation,
|
||||
'path' => $recordingPath,
|
||||
'path' => $recordingPath,
|
||||
]
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
$broadcast = $this->broadcastRepo->findByPath($station, $recordingPath);
|
||||
$broadcast = $this->broadcastRepo->getOrCreateFromPath($station, $recordingPath);
|
||||
if (null !== $broadcast) {
|
||||
if (0 === $broadcast->getTimestampEnd()) {
|
||||
$broadcast->setTimestampEnd($file->getMTime() ?: time());
|
||||
}
|
||||
|
||||
$this->em->persist($broadcast);
|
||||
$this->em->flush();
|
||||
|
||||
$tempPath = $file->getPathname();
|
||||
$fs->uploadAndDeleteOriginal($tempPath, $recordingPath);
|
||||
|
||||
|
@ -91,7 +98,7 @@ class MoveBroadcastsTask extends AbstractTask
|
|||
'Uploaded broadcast to storage location.',
|
||||
[
|
||||
'storageLocation' => (string)$storageLocation,
|
||||
'path' => $recordingPath,
|
||||
'path' => $recordingPath,
|
||||
]
|
||||
);
|
||||
} else {
|
||||
|
@ -100,7 +107,7 @@ class MoveBroadcastsTask extends AbstractTask
|
|||
$this->logger->info(
|
||||
'Could not find a corresponding broadcast.',
|
||||
[
|
||||
'path' => $recordingPath,
|
||||
'path' => $recordingPath,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue