Add "Source" tab to Podcast modal and wire up select API request.

This commit is contained in:
Buster Neece 2024-02-22 15:59:31 -06:00
parent b0ab0916ae
commit e3dfe85653
No known key found for this signature in database
5 changed files with 180 additions and 0 deletions

View File

@ -125,6 +125,9 @@ return static function (RouteCollectorProxy $group) {
$group->post('/podcasts/art', Controller\Api\Stations\Podcasts\Art\PostArtAction::class)
->setName('api:stations:podcasts:new-art');
$group->get('/podcasts/playlists', Controller\Api\Stations\Podcasts\PlaylistsAction::class)
->setName('api:stations:podcasts:playlists');
$group->group(
'/podcast/{podcast_id}',
function (RouteCollectorProxy $group) {

View File

@ -15,6 +15,10 @@
:language-options="languageOptions"
/>
<podcast-form-source
:form="form"
/>
<podcast-common-artwork
v-model="form.artwork_file"
:artwork-src="record.links.art"
@ -26,6 +30,7 @@
<script setup lang="ts">
import PodcastFormBasicInfo from './PodcastForm/BasicInfo.vue';
import PodcastFormSource from './PodcastForm/Source.vue';
import PodcastCommonArtwork from './Common/Artwork.vue';
import mergeExisting from "~/functions/mergeExisting";
import {baseEditModalProps, ModalFormTemplateRef, useBaseEditModal} from "~/functions/useBaseEditModal";

View File

@ -0,0 +1,128 @@
<template>
<tab
:label="$gettext('Source')"
:item-header-class="tabClass"
>
<div class="row g-3">
<form-group-multi-check
id="edit_form_source"
class="col-md-12"
:field="v$.source"
:options="sourceOptions"
stacked
radio
:label="$gettext('Source')"
/>
</div>
<section
v-show="form.source === 'playlist'"
class="card mb-3"
role="region"
>
<div class="card-header text-bg-primary">
<h2 class="card-title">
{{ $gettext('Playlist-Based Podcast') }}
</h2>
</div>
<div class="card-body">
<p>
{{
$gettext('Playlist-based podcasts will automatically sync with the contents of a playlist, creating new podcast episodes for any media added to the playlist.')
}}
</p>
<loading :loading="playlistsLoading">
<div class="row g-3 mb-3">
<form-group-select
id="form_edit_playlist_id"
class="col-md-12"
:field="v$.playlist_id"
:options="playlistOptions"
:label="$gettext('Select Playlist')"
/>
<form-group-checkbox
id="form_edit_playlist_auto_publish"
class="col-md-12"
:field="v$.playlist_auto_publish"
:label="$gettext('Automatically Publish New Episodes')"
:description="$gettext('Whether new episodes should be marked as published or held for review as unpublished.')"
/>
</div>
</loading>
</div>
</section>
</tab>
</template>
<script setup lang="ts">
import FormGroupSelect from "~/components/Form/FormGroupSelect.vue";
import {useVModel} from "@vueuse/core";
import {useVuelidateOnFormTab} from "~/functions/useVuelidateOnFormTab";
import {required} from "@vuelidate/validators";
import Tab from "~/components/Common/Tab.vue";
import FormGroupMultiCheck from "~/components/Form/FormGroupMultiCheck.vue";
import FormGroupCheckbox from "~/components/Form/FormGroupCheckbox.vue";
import {useTranslate} from "~/vendor/gettext.ts";
import {onMounted, ref, shallowRef} from "vue";
import {useAxios} from "~/vendor/axios.ts";
import objectToFormOptions from "~/functions/objectToFormOptions.ts";
import {getStationApiUrl} from "~/router.ts";
import Loading from "~/components/Common/Loading.vue";
const props = defineProps({
form: {
type: Object,
required: true
}
});
const emit = defineEmits(['update:form']);
const form = useVModel(props, 'form', emit);
const {v$, tabClass} = useVuelidateOnFormTab(
{
source: {required},
playlist_id: {},
playlist_auto_publish: {}
},
form,
{
source: 'manual',
playlist_id: null,
playlist_auto_publish: true,
}
);
const {$gettext} = useTranslate();
const sourceOptions = [
{
value: 'manual',
text: $gettext('Manually Add Episodes'),
description: $gettext('Create podcast episodes independent of your station\'s media collection.')
},
{
value: 'playlist',
text: $gettext('Synchronize with Playlist'),
description: $gettext('Automatically create new podcast episodes when media is added to a specified playlist.')
}
];
const playlistsLoading = ref(true);
const playlistOptions = shallowRef([]);
const {axios} = useAxios();
const playlistsApiUrl = getStationApiUrl('/podcasts/playlists');
const loadPlaylists = () => {
axios.get(playlistsApiUrl.value).then((resp) => {
playlistOptions.value = objectToFormOptions(resp.data);
}).finally(() => {
playlistsLoading.value = false;
});
};
onMounted(loadPlaylists);
</script>

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Controller\Api\Stations\Podcasts;
use App\Container\EntityManagerAwareTrait;
use App\Controller\SingleActionInterface;
use App\Entity\Enums\PlaylistSources;
use App\Http\Response;
use App\Http\ServerRequest;
use Psr\Http\Message\ResponseInterface;
final class PlaylistsAction implements SingleActionInterface
{
use EntityManagerAwareTrait;
public function __invoke(
ServerRequest $request,
Response $response,
array $params
): ResponseInterface {
$playlistsRaw = $this->em->createQuery(
<<<'DQL'
SELECT sp.id, sp.name
FROM App\Entity\StationPlaylist sp
WHERE sp.station = :station
AND sp.source = :sourceSongs
DQL
)->setParameter('station', $request->getStation())
->setParameter('sourceSongs', PlaylistSources::Songs->value)
->getArrayResult();
return $response->withJson(
array_column($playlistsRaw, 'name', 'id')
);
}
}

View File

@ -302,6 +302,12 @@ final class PodcastsController extends AbstractApiCrudController
unset($data['categories']);
}
if (isset($data['playlist_id'])) {
$data['playlist'] = $data['playlist_id'];
unset($data['playlist_id']);
}
$record = parent::fromArray($data, $record, $context);
if (null !== $newCategories) {