diff --git a/Dockerfile b/Dockerfile index e64845f1334..1a30fd71865 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN go install github.com/jwilder/dockerize@v0.9.2 RUN go install github.com/aptible/supercronic@v0.2.33 -RUN go install github.com/centrifugal/centrifugo/v6@v6.0.0 +RUN go install github.com/centrifugal/centrifugo/v5@v5.4.9 RUN strip /go/bin/* diff --git a/backend/src/Controller/Frontend/PublicPages/PodcastsAction.php b/backend/src/Controller/Frontend/PublicPages/PodcastsAction.php index 9b3a1aad211..65192d018d4 100644 --- a/backend/src/Controller/Frontend/PublicPages/PodcastsAction.php +++ b/backend/src/Controller/Frontend/PublicPages/PodcastsAction.php @@ -58,7 +58,9 @@ public function __invoke( 'hide_footer' => $isEmbedded, ], props: [ + 'stationId' => $station->getIdRequired(), 'stationName' => $station->getName(), + 'stationTz' => $station->getTimezone(), 'baseUrl' => $router->fromHere('public:index'), 'groupLayout' => $groupLayout, ], diff --git a/frontend/components/Public/Podcasts/Podcast.vue b/frontend/components/Public/Podcasts/Podcast.vue index 842d5129e50..44b785458d4 100644 --- a/frontend/components/Public/Podcasts/Podcast.vue +++ b/frontend/components/Public/Podcasts/Podcast.vue @@ -182,14 +182,16 @@ import PlayButton from "~/components/Common/PlayButton.vue"; import useStationDateTimeFormatter from "~/functions/useStationDateTimeFormatter.ts"; import PodcastCommon from "./PodcastCommon.vue"; import GridLayout from "~/components/Common/GridLayout.vue"; -import {usePodcastGroupLayout} from "~/components/Public/Podcasts/usePodcastGroupLayout.ts"; import {ApiPodcast, ApiPodcastEpisode} from "~/entities/ApiInterfaces.ts"; +import {usePodcastGlobals} from "~/components/Public/Podcasts/usePodcastGlobals.ts"; +import {computed} from "vue"; -const {groupLayout} = usePodcastGroupLayout(); +const {groupLayout, stationId, stationTz} = usePodcastGlobals(); -const {params} = useRoute(); - -const podcastUrl = getStationApiUrl(`/public/podcast/${params.podcast_id}`); +const podcastUrl = getStationApiUrl(computed(() => { + const {params} = useRoute(); + return `/public/podcast/${params.podcast_id}`; +}), stationId); const {axios} = useAxios(); const {state: podcast, isLoading} = useRefreshableAsyncState( @@ -197,7 +199,10 @@ const {state: podcast, isLoading} = useRefreshableAsyncState( {}, ); -const episodesUrl = getStationApiUrl(`/public/podcast/${params.podcast_id}/episodes`); +const episodesUrl = getStationApiUrl(computed(() => { + const {params} = useRoute(); + return `/public/podcast/${params.podcast_id}/episodes`; +}), stationId); const {$gettext} = useTranslate(); const fields: DataTableField[] = [ @@ -207,5 +212,5 @@ const fields: DataTableField[] = [ {key: 'actions', label: $gettext('Actions'), sortable: false, class: 'shrink'} ]; -const {formatTimestampAsDateTime} = useStationDateTimeFormatter(); +const {formatTimestampAsDateTime} = useStationDateTimeFormatter(stationTz); diff --git a/frontend/components/Public/Podcasts/PodcastEpisode.vue b/frontend/components/Public/Podcasts/PodcastEpisode.vue index db8fd3716e1..9438b7a82ce 100644 --- a/frontend/components/Public/Podcasts/PodcastEpisode.vue +++ b/frontend/components/Public/Podcasts/PodcastEpisode.vue @@ -101,11 +101,20 @@ import AlbumArt from "~/components/Common/AlbumArt.vue"; import PlayButton from "~/components/Common/PlayButton.vue"; import useStationDateTimeFormatter from "~/functions/useStationDateTimeFormatter.ts"; import PodcastCommon from "./PodcastCommon.vue"; +import {usePodcastGlobals} from "~/components/Public/Podcasts/usePodcastGlobals.ts"; +import {computed} from "vue"; -const {params} = useRoute(); +const {stationId, stationTz} = usePodcastGlobals(); -const podcastUrl = getStationApiUrl(`/public/podcast/${params.podcast_id}`); -const episodeUrl = getStationApiUrl(`/public/podcast/${params.podcast_id}/episode/${params.episode_id}`); +const podcastUrl = getStationApiUrl(computed(() => { + const {params} = useRoute(); + return `/public/podcast/${params.podcast_id}`; +}), stationId); + +const episodeUrl = getStationApiUrl(computed(() => { + const {params} = useRoute(); + return `/public/podcast/${params.podcast_id}/episode/${params.episode_id}`; +}), stationId); const {axios} = useAxios(); @@ -119,5 +128,5 @@ const {state: episode, isLoading: episodeLoading} = useRefreshableAsyncState( {}, ); -const {formatTimestampAsDateTime} = useStationDateTimeFormatter(); +const {formatTimestampAsDateTime} = useStationDateTimeFormatter(stationTz); diff --git a/frontend/components/Public/Podcasts/PodcastList.vue b/frontend/components/Public/Podcasts/PodcastList.vue index 47e8da91f67..cbafe98ba52 100644 --- a/frontend/components/Public/Podcasts/PodcastList.vue +++ b/frontend/components/Public/Podcasts/PodcastList.vue @@ -124,13 +124,13 @@ import {getStationApiUrl} from "~/router.ts"; import {useTranslate} from "~/vendor/gettext.ts"; import {IconRss} from "~/components/Common/icons.ts"; import Icon from "~/components/Common/Icon.vue"; -import {usePodcastGroupLayout} from "~/components/Public/Podcasts/usePodcastGroupLayout.ts"; import GridLayout from "~/components/Common/GridLayout.vue"; import {ApiPodcast} from "~/entities/ApiInterfaces.ts"; +import {usePodcastGlobals} from "~/components/Public/Podcasts/usePodcastGlobals.ts"; -const {groupLayout} = usePodcastGroupLayout(); +const {groupLayout, stationId} = usePodcastGlobals(); -const apiUrl = getStationApiUrl('/public/podcasts'); +const apiUrl = getStationApiUrl('/public/podcasts', stationId); const {$gettext} = useTranslate(); diff --git a/frontend/components/Public/Podcasts/PodcastsLayout.vue b/frontend/components/Public/Podcasts/PodcastsLayout.vue index 550c3ec73c3..2756afe4827 100644 --- a/frontend/components/Public/Podcasts/PodcastsLayout.vue +++ b/frontend/components/Public/Podcasts/PodcastsLayout.vue @@ -26,18 +26,14 @@ import FullHeightCard from "~/components/Public/FullHeightCard.vue"; import InlinePlayer from "~/components/InlinePlayer.vue"; import MinimalLayout from "~/components/MinimalLayout.vue"; -import {useProvidePodcastGroupLayout} from "~/components/Public/Podcasts/usePodcastGroupLayout.ts"; +import {PodcastLayoutProps, useProvidePodcastGlobals} from "~/components/Public/Podcasts/usePodcastGlobals.ts"; const props = withDefaults( - defineProps<{ - stationName: string | null, - baseUrl: string, - groupLayout?: string, - }>(), + defineProps(), { groupLayout: 'table' } ); -useProvidePodcastGroupLayout(props.groupLayout); +useProvidePodcastGlobals(props); diff --git a/frontend/components/Public/Podcasts/usePodcastGlobals.ts b/frontend/components/Public/Podcasts/usePodcastGlobals.ts new file mode 100644 index 00000000000..8f6ff07d484 --- /dev/null +++ b/frontend/components/Public/Podcasts/usePodcastGlobals.ts @@ -0,0 +1,15 @@ +import {createInjectionState} from "@vueuse/shared"; + +export interface PodcastLayoutProps { + stationId: string | number, + stationName: string | null, + stationTz: string, + baseUrl: string, + groupLayout?: string, +} + +const [useProvidePodcastGlobals, usePodcastGlobals] = createInjectionState( + (props: PodcastLayoutProps) => props, +); + +export {useProvidePodcastGlobals, usePodcastGlobals}; diff --git a/frontend/components/Public/Podcasts/usePodcastGroupLayout.ts b/frontend/components/Public/Podcasts/usePodcastGroupLayout.ts deleted file mode 100644 index f7e2fbccb2a..00000000000 --- a/frontend/components/Public/Podcasts/usePodcastGroupLayout.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {ref, Ref} from "vue"; -import {createInjectionState} from "@vueuse/shared"; - -const [useProvidePodcastGroupLayout, usePodcastGroupLayout] = createInjectionState( - (initialGroupLayout: string) => { - const groupLayout: Ref = ref(initialGroupLayout); - - return { - groupLayout - }; - } -); - -export {useProvidePodcastGroupLayout, usePodcastGroupLayout}; diff --git a/frontend/functions/useStationDateTimeFormatter.ts b/frontend/functions/useStationDateTimeFormatter.ts index 35d2da4f6a6..f937b0c8147 100644 --- a/frontend/functions/useStationDateTimeFormatter.ts +++ b/frontend/functions/useStationDateTimeFormatter.ts @@ -2,10 +2,20 @@ import {useLuxon} from "~/vendor/luxon.ts"; import {useAzuraCast, useAzuraCastStation} from "~/vendor/azuracast.ts"; import {DateTimeMaybeValid} from "luxon"; -export default function useStationDateTimeFormatter() { +export default function useStationDateTimeFormatter( + timezone?: string +) { const {DateTime} = useLuxon(); const {timeConfig} = useAzuraCast(); - const {timezone} = useAzuraCastStation(); + + if (!timezone) { + const station = useAzuraCastStation(); + if (station) { + timezone = station.timezone; + } else { + throw new Error("Cannot get timezone!"); + } + } const now = (): DateTimeMaybeValid => DateTime.local({zone: timezone}); diff --git a/frontend/router.ts b/frontend/router.ts index 9dc73acf3c9..9d39143ca10 100644 --- a/frontend/router.ts +++ b/frontend/router.ts @@ -1,5 +1,5 @@ +import {computed, ComputedRef, MaybeRefOrGetter, toValue} from "vue"; import {useAzuraCastStation} from "~/vendor/azuracast.ts"; -import {computed, ComputedRef} from "vue"; export function getApiUrl(suffix: string): ComputedRef { return computed((): string => { @@ -7,11 +7,24 @@ export function getApiUrl(suffix: string): ComputedRef { }); } -export function getStationApiUrl(suffix: string): ComputedRef { - const {id} = useAzuraCastStation(); +export function getStationApiUrl( + suffix: MaybeRefOrGetter, + id?: MaybeRefOrGetter +): ComputedRef { + if (!id) { + const station = useAzuraCastStation(); + if (station) { + id = station.id; + } else { + throw new Error("Can't find station ID!"); + } + } return computed((): string => { - const stationSuffix = `/station/${id}${suffix}`; + const idValue = toValue(id); + const suffixValue = toValue(suffix); + + const stationSuffix = `/station/${idValue}${suffixValue}`; return getApiUrl(stationSuffix).value; }); } diff --git a/util/docker/stations/setup/liquidsoap.sh b/util/docker/stations/setup/liquidsoap.sh index 0ee8620eb40..edee4ab9ddd 100644 --- a/util/docker/stations/setup/liquidsoap.sh +++ b/util/docker/stations/setup/liquidsoap.sh @@ -18,7 +18,9 @@ if [[ "$(uname -m)" = "aarch64" ]]; then ARCHITECTURE=arm64 fi -wget -O /tmp/liquidsoap.deb "https://github.com/savonet/liquidsoap-release-assets/releases/download/rolling-release-v2.3.x/liquidsoap-c0cd13a_2.3.1-debian-bookworm-1_${ARCHITECTURE}.deb" +# Temporarily use 2.3.0 until upstream RRs are fixed +# wget -O /tmp/liquidsoap.deb "https://github.com/savonet/liquidsoap-release-assets/releases/download/rolling-release-v2.3.x/liquidsoap-c0cd13a_2.3.1-debian-bookworm-1_${ARCHITECTURE}.deb" +wget -O /tmp/liquidsoap.deb "https://github.com/savonet/liquidsoap/releases/download/v2.3.0/liquidsoap_2.3.0-debian-bookworm-1_${ARCHITECTURE}.deb" dpkg -i /tmp/liquidsoap.deb apt-get install -y -f --no-install-recommends