@saooti/octopus-sdk 41.12.0-beta3 → 41.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 41.12.0 (En cours)
3
+ ## 41.12.0 (13/07/2026)
4
4
 
5
5
  **Features**
6
6
 
@@ -21,11 +21,15 @@
21
21
  - Ajout de nouvelles options d'apparence pour `ClassicButton`
22
22
  - Changement propriété principale de `ClassicButtonGroup` pour plus de cohérence
23
23
  - Ajout de variables CSS pour configurer l'aspect de divers boutons
24
+ - Ajout d'une propriété SDK permettant d'afficher des tags sur les éléments de
25
+ type `PresentationItem`
26
+ - Ajout de l'api `rubriqueApi`
24
27
 
25
28
  **Fixes**
26
29
 
27
30
  - Correction d'une exception dans `deepEquals` si la comparaison est faite entre
28
31
  une variable primitive et un objet
32
+ - Correction du placement du header `PodcastmakerHeader`
29
33
 
30
34
  **Misc**
31
35
 
package/index.ts CHANGED
@@ -194,7 +194,7 @@ export {
194
194
  type ProviderTts,
195
195
  type Voice
196
196
  } from "./src/stores/class/transcript/transcriptParams.ts";
197
- export { type Canal } from "./src/stores/class/radio/canal.ts";
197
+ export * from "./src/stores/class/radio/canal";
198
198
  export { type Cartouchier } from "./src/stores/class/cartouchier/cartouchier.ts";
199
199
  export { type Cartouche, emptyCartouche } from "./src/stores/class/cartouchier/cartouche.ts";
200
200
  export { type PlaylistMedia } from "./src/stores/class/radio/playlistMedia";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "41.12.0-beta3",
3
+ "version": "41.12.0",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
package/src/api/index.ts CHANGED
@@ -7,3 +7,4 @@ export { podcastApi, PodcastSort, type PodcastSearchOptions } from "./podcastApi
7
7
  export { radioApi } from "./radioApi";
8
8
  export * from "./aggregatorsApi";
9
9
  export * from "./mediathequeApi";
10
+ export * from "./rubriquesApi";
@@ -1,4 +1,4 @@
1
- import { Canal } from "../stores/class/radio/canal";
1
+ import { Ambiance, Canal } from "../stores/class/radio/canal";
2
2
  import classicApi from "./classicApi";
3
3
  import { ModuleApi } from "./apiConnection";
4
4
 
@@ -26,7 +26,23 @@ async function getAll(organisationId: string): Promise<Array<Canal>> {
26
26
  });
27
27
  }
28
28
 
29
+ /**
30
+ * Set the default ambiance for the given canal
31
+ * @param canalId ID of the canal to change
32
+ * @param ambiance New ambiance settings
33
+ * @returns The modified ambiance
34
+ */
35
+ async function setDefaultAmbiance(canalId: number, ambiance: Ambiance): Promise<Ambiance> {
36
+ return await classicApi.putData<Ambiance>({
37
+ api: ModuleApi.RADIO,
38
+ path: `ambiance/canal/${canalId}/default`,
39
+ dataToSend: ambiance
40
+ });
41
+
42
+ }
43
+
29
44
  export const radioApi = {
30
45
  get,
31
- getAll
46
+ getAll,
47
+ setDefaultAmbiance
32
48
  };
@@ -0,0 +1,68 @@
1
+ import { classicApi, ModuleApi } from "@saooti/octopus-sdk";
2
+ import { Rubrique } from "@/stores/class/rubrique/rubrique";
3
+ import { Rubriquage } from "@/stores/class/rubrique/rubriquage";
4
+ import { useCacheStore } from "../stores/CacheStore";
5
+
6
+ /**
7
+ * Find rubriquages according to criterias
8
+ * @param organisationIds List of organisation IDs for which to retrieve the
9
+ * rubriquage
10
+ * @param searchOptions Additional search options
11
+ */
12
+ async function searchRubriquages(organisationIds: Array<string>, searchOptions?: {
13
+ rubriquageId?: number;
14
+ organisationId?: string|Array<string>;
15
+ query?: string;
16
+ }): Promise<Array<Rubriquage>> {
17
+ return classicApi.fetchData<Array<Rubriquage>>({
18
+ api: ModuleApi.DEFAULT,
19
+ path: 'rubriquage/find',
20
+ parameters: {
21
+ organisationId: organisationIds,
22
+ ...searchOptions
23
+ }
24
+ });
25
+ }
26
+
27
+ async function searchRubriques(searchOptions?: {
28
+ rubriquageId?: number;
29
+ organisationId?: string|Array<string>;
30
+ query?: string;
31
+ }): Promise<Array<Rubrique>> {
32
+ return classicApi.fetchData<Array<Rubrique>>({
33
+ api: ModuleApi.DEFAULT,
34
+ path: 'rubrique/search',
35
+ parameters: searchOptions
36
+ });
37
+ }
38
+
39
+ /**
40
+ * Fetch rubrique data by ID
41
+ * @see getCachedRubrique
42
+ * @param rubriqueId ID of the rubrique to fetch
43
+ * @returns The rubrique
44
+ */
45
+ async function getRubrique(rubriqueId: number): Promise<Rubrique> {
46
+ return classicApi.fetchData<Rubrique>({
47
+ api: ModuleApi.DEFAULT,
48
+ path: `rubrique/${rubriqueId}`
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Fetch rubrique data by ID
54
+ * If the rubrique is available in the cache, return it from the cache
55
+ * @param rubriqueId ID of the rubrique to fetch
56
+ * @returns The rubrique
57
+ */
58
+ async function getCachedRubrique(rubriqueId: number): Promise<Rubrique> {
59
+ const cacheStore = useCacheStore();
60
+ return cacheStore.getData(`rubrique-${rubriqueId}`, () => getRubrique(rubriqueId));
61
+ }
62
+
63
+ export const rubriquesApi = {
64
+ getRubrique,
65
+ getCachedRubrique,
66
+ searchRubriquages,
67
+ searchRubriques
68
+ };
@@ -0,0 +1,78 @@
1
+ import { Emission } from "@/stores/class/general/emission";
2
+ import { state } from "../../stores/ParamSdkStore";
3
+ import { useGeneralStore } from "../../stores/GeneralStore";
4
+ import { Podcast } from "../../stores/class/general/podcast";
5
+ import { rubriquesApi } from "../../api";
6
+ import { useDayjs } from "./useDayjs";
7
+
8
+ export const usePresentationItem = () => {
9
+ const generalStore = useGeneralStore();
10
+ const { formatDate } = useDayjs();
11
+
12
+ function iabTags(emission: Emission): Array<string> {
13
+ return generalStore.storedCategories
14
+ .filter(cat => emission.iabIds.includes(cat.id))
15
+ .map(cat => cat.name);
16
+ }
17
+
18
+ async function rubriqueTags(element: Podcast|Emission): Promise<Array<string>> {
19
+ const rubriqueIds: Array<number> = [];
20
+ if (element.rubriqueIds) {
21
+ rubriqueIds.push(...element.rubriqueIds);
22
+ }
23
+ if ('emission' in element && element.emission.rubriqueIds) {
24
+ rubriqueIds.push(...element.emission.rubriqueIds);
25
+ }
26
+ const promises = rubriqueIds.map(rubriquesApi.getCachedRubrique);
27
+ const rubriques = await Promise.all(promises);
28
+
29
+ if (state.presentationItems.tagsRubriquageId) {
30
+ const rubriquageId = state.presentationItems.tagsRubriquageId;
31
+ return rubriques.filter(r => r.rubriquageId === rubriquageId).map(r => r.name);
32
+ } else {
33
+ return rubriques.map(r => r.name);
34
+ }
35
+ }
36
+
37
+ async function tagsFor(element: Podcast|Emission): Promise<Array<string>|undefined> {
38
+ const type = state.presentationItems.tags;
39
+ let tags: Array<string>|undefined = undefined;
40
+ if (type === 'iab') {
41
+ const emission = 'emission' in element ? element.emission : element;
42
+ tags = iabTags(emission);
43
+ } else if (type === 'rubrique') {
44
+ tags = await rubriqueTags(element);
45
+ }
46
+
47
+ if (tags && state.presentationItems.tagsLimit) {
48
+ return tags.slice(0, state.presentationItems.tagsLimit);
49
+ }
50
+
51
+ return tags;
52
+ }
53
+
54
+ function additionalInfoFor(element: Podcast|Emission): Array<string>|undefined {
55
+ const prop = state.presentationItems.additionalInfo;
56
+ if (!prop?.length) {
57
+ return undefined;
58
+ }
59
+
60
+ const podcast = 'emission' in element ? element : null;
61
+ const emission = podcast?.emission ?? element as Emission;
62
+
63
+ return prop.map(property => {
64
+ if (property === 'date') {
65
+ if (podcast?.pubDate) {
66
+ return formatDate(podcast.pubDate);
67
+ } else {
68
+ return null;
69
+ }
70
+ } else if (property === 'productor') {
71
+ return emission.orga.name;
72
+ }
73
+ return null;
74
+ }).filter(p => p !== null);
75
+ }
76
+
77
+ return { tagsFor, additionalInfoFor };
78
+ };
@@ -30,7 +30,7 @@
30
30
  <router-link
31
31
  v-if="href"
32
32
  :to="href"
33
- class="btn btn-primary align-self-center w-fit-content m-4"
33
+ class="btn btn-primary align-self-center w-fit-content m-4 icon-available"
34
34
  >
35
35
  {{ buttonText }}
36
36
  </router-link>
@@ -2,33 +2,42 @@
2
2
  Component to display an emission with its description
3
3
  -->
4
4
  <template>
5
- <PresentationItem
6
- :name="emission.name"
7
- :route="route"
8
- :image-url="emission.imageUrl"
9
- :description="isDescription ? emission.description : undefined"
10
- :vertical="isVertical"
11
- />
5
+ <PresentationItem
6
+ :name="emission.name"
7
+ :route="route"
8
+ :image-url="emission.imageUrl"
9
+ :description="isDescription ? emission.description : undefined"
10
+ :vertical="isVertical"
11
+ :tags="tags"
12
+ :additional-info="additionalInfoFor(emission)"
13
+ />
12
14
  </template>
13
15
 
14
16
  <script setup lang="ts">
15
17
  import { Emission } from "@/stores/class/general/emission";
16
18
  import PresentationItem from "../../layouts/PresentationItem.vue";
17
- import { computed } from "vue";
19
+ import { computed, ref, watch } from "vue";
18
20
  import { RouteLocationRaw } from "vue-router";
21
+ import { usePresentationItem } from "../../composable/usePresentationItem";
19
22
 
20
23
  //Props
21
24
  const props = defineProps<{
22
- /** The emission to display */
23
- emission: Emission;
24
- /** When true display the card vertically */
25
- isVertical?: boolean;
26
- /** When true also display the description */
27
- isDescription?: boolean;
25
+ /** The emission to display */
26
+ emission: Emission;
27
+ /** When true display the card vertically */
28
+ isVertical?: boolean;
29
+ /** When true also display the description */
30
+ isDescription?: boolean;
28
31
  }>();
29
32
 
33
+ const tags = ref([]);
34
+ const { tagsFor, additionalInfoFor } = usePresentationItem();
35
+
36
+ watch(props.emission, async () => {
37
+ tags.value = await tagsFor(props.emission);
38
+ }, { immediate: true });
39
+
30
40
  const route = computed((): RouteLocationRaw => {
31
- return { name: 'emission', params: { emissionId: props.emission.emissionId } };
41
+ return { name: 'emission', params: { emissionId: props.emission.emissionId } };
32
42
  });
33
-
34
43
  </script>
@@ -1,72 +1,87 @@
1
1
  <template>
2
- <div class="page-element-title-container">
3
- <div class="page-element-title">
4
- <h1>{{ pageTitle }}</h1>
2
+ <div class="page-element-title-container">
3
+ <div class="page-element-title">
4
+ <h1>{{ pageTitle }}</h1>
5
+ </div>
6
+ <div class="page-element-bg" :style="backgroundDisplay" />
5
7
  </div>
6
- <div class="page-element-bg" :style="backgroundDisplay" />
7
- </div>
8
8
  </template>
9
9
 
10
10
  <script setup lang="ts">
11
- import { computed } from "vue";
12
- import {useImageProxy} from "../../composable/useImageProxy";
11
+ import { computed, onMounted } from "vue";
12
+ import { useImageProxy } from "../../composable/useImageProxy";
13
13
 
14
14
  //Props
15
15
  const props = defineProps({
16
- pageTitle: { default: undefined, type: String },
17
- imgUrl: { default: undefined, type: String },
16
+ pageTitle: { default: undefined, type: String },
17
+ imgUrl: { default: undefined, type: String },
18
18
  })
19
19
 
20
+ onMounted(() => {
21
+ const elt = document.querySelector('.page-element-title-container');
22
+
23
+ // Retrieve header
24
+ const header = document.getElementsByTagName('header');
25
+ if (header.length) {
26
+ // Get header height
27
+ const height = (header[0] as HTMLElement).offsetHeight;
28
+ // Update PM header position according to header height
29
+ elt.style.setProperty('--top', height + 'px');
30
+ }
31
+ });
32
+
20
33
  //Composables
21
34
  const { useProxyImageUrl } = useImageProxy();
22
35
 
23
36
  //Computed
24
37
  const backgroundDisplay = computed(() => {
25
- if (!props.imgUrl) {
26
- return "";
27
- }
28
- return `background-image: url('${useProxyImageUrl(
29
- props.imgUrl,
30
- "250",
31
- )}');`;
38
+ if (!props.imgUrl) {
39
+ return "";
40
+ }
41
+ return `background-image: url('${useProxyImageUrl(
42
+ props.imgUrl,
43
+ "250",
44
+ )}');`;
32
45
  });
33
46
  </script>
34
47
 
35
48
  <style lang="scss">
36
49
  .octopus-app {
37
- .page-element.page-element-podcastmaker {
38
- margin-top: 11rem;
39
- }
50
+ .page-element.page-element-podcastmaker {
51
+ margin-top: 11rem;
52
+ }
40
53
 
41
- .page-element-title-container {
42
- background: black;
43
- position: absolute;
44
- right: 0;
45
- left: 0;
46
- top: 0;
54
+ .page-element-title-container {
55
+ --top: 0;
47
56
 
48
- .page-element-bg {
49
- height: 15rem;
50
- opacity: 0.5;
51
- filter: blur(8px);
52
- background-position: center;
53
- background-repeat: no-repeat;
54
- background-size: cover;
55
- }
57
+ background: black;
58
+ position: absolute;
59
+ right: 0;
60
+ left: 0;
61
+ top: var(--top);
62
+
63
+ .page-element-bg {
64
+ height: 15rem;
65
+ opacity: 0.5;
66
+ filter: blur(8px);
67
+ background-position: center;
68
+ background-repeat: no-repeat;
69
+ background-size: cover;
70
+ }
56
71
 
57
- .page-element-title {
58
- position: absolute;
59
- inset: 0;
60
- z-index: 2;
61
- display: flex;
62
- justify-content: center;
63
- align-items: center;
72
+ .page-element-title {
73
+ position: absolute;
74
+ inset: 0;
75
+ z-index: 2;
76
+ display: flex;
77
+ justify-content: center;
78
+ align-items: center;
64
79
 
65
- h1 {
66
- color: white !important;
67
- font-size: 2rem;
68
- }
80
+ h1 {
81
+ color: white !important;
82
+ font-size: 2rem;
83
+ }
84
+ }
69
85
  }
70
- }
71
86
  }
72
87
  </style>
@@ -2,37 +2,39 @@
2
2
  Simple component to display a few podcasts
3
3
  -->
4
4
  <template>
5
- <PresentationLayout
6
- v-if="!loading && !error"
7
- :title="title"
8
- :items="podcasts"
9
- :route="href"
10
- :button-text="buttonText"
11
- >
12
- <template #item="{ item, first }">
13
- <PresentationItem
14
- :class="!isPhone && first ? 'me-3' : ''"
15
- :name="item.title"
16
- :route="route(item)"
17
- :image-url="item.imageUrl"
18
- :description="item.description"
19
- :vertical="!isPhone && first"
20
- >
21
- <template #after-image>
22
- <PodcastPlayButton
23
- :podcast="item"
24
- :hide-play="false"
25
- :show-processing="false"
26
- />
5
+ <PresentationLayout
6
+ v-if="!loading && !error"
7
+ :title="title"
8
+ :items="podcasts"
9
+ :route="href"
10
+ :button-text="buttonText"
11
+ >
12
+ <template #item="{ item, first }">
13
+ <PresentationItem
14
+ :class="!isPhone && first ? 'me-3' : ''"
15
+ :name="item.title"
16
+ :route="route(item)"
17
+ :image-url="item.imageUrl"
18
+ :description="item.description"
19
+ :vertical="!isPhone && first"
20
+ :tags="tags.get(item.podcastId)"
21
+ :additional-info="additionalInfoFor(item)"
22
+ >
23
+ <template #after-image>
24
+ <PodcastPlayButton
25
+ :podcast="item"
26
+ :hide-play="false"
27
+ :show-processing="false"
28
+ />
29
+ </template>
30
+ </PresentationItem>
27
31
  </template>
28
- </PresentationItem>
29
- </template>
30
- </PresentationLayout>
31
- <ClassicLoading
32
- v-else
33
- :loading-text="loading ? $t('Loading emissions ...') : undefined"
34
- :error-text="error ? $t(`Error`) : undefined"
35
- />
32
+ </PresentationLayout>
33
+ <ClassicLoading
34
+ v-else
35
+ :loading-text="loading ? $t('Loading emissions ...') : undefined"
36
+ :error-text="error ? $t(`Error`) : undefined"
37
+ />
36
38
  </template>
37
39
 
38
40
  <script setup lang="ts">
@@ -40,7 +42,7 @@ import classicApi from "../../../api/classicApi";
40
42
  import {useErrorHandler} from "../../composable/useErrorHandler";
41
43
  import ClassicLoading from "../../form/ClassicLoading.vue";
42
44
  import { Emission } from "@/stores/class/general/emission";
43
- import { onMounted, Ref, ref } from "vue";
45
+ import { onMounted, reactive, Ref, ref, watch } from "vue";
44
46
  import { AxiosError } from "axios";
45
47
  import {useResizePhone} from "../../composable/useResizePhone";
46
48
  import { ListClassicReturn } from "../../../stores/class/general/listReturn";
@@ -52,89 +54,101 @@ import PresentationItem from "../../layouts/PresentationItem.vue";
52
54
  import PodcastPlayButton from "./PodcastPlayButton.vue";
53
55
  import { RouteLocationRaw } from "vue-router";
54
56
  import { podcastApi, PodcastSort } from "../../../api/podcastApi";
57
+ import { usePresentationItem } from "../../composable/usePresentationItem";
55
58
 
56
59
  //Props
57
60
  const props = defineProps({
58
- organisationId: { default: undefined, type: String },
59
- title: { default: "", type: String },
60
- href: { default: undefined, type: String },
61
- buttonText: { default: undefined, type: String },
62
- isDescription: { default: false, type: Boolean },
63
- rubriquesId: { default: [], type: Array<number> },
61
+ organisationId: { default: undefined, type: String },
62
+ title: { default: "", type: String },
63
+ href: { default: undefined, type: String },
64
+ buttonText: { default: undefined, type: String },
65
+ isDescription: { default: false, type: Boolean },
66
+ rubriquesId: { default: [], type: Array<number> },
64
67
  })
65
68
 
66
69
  //Data
67
70
  const loading = ref(true);
68
71
  const error = ref(false);
69
72
  const podcasts: Ref<Array<Podcast>> = ref([]);
73
+ const tags = reactive(new Map<number, Array<string>>());
70
74
 
71
75
  //Composables
72
76
  const { isPhone } = useResizePhone();
73
- const {handle403} = useErrorHandler();
77
+ const { handle403 } = useErrorHandler();
78
+ const { tagsFor, additionalInfoFor } = usePresentationItem();
74
79
 
75
- onMounted(()=>fetchNext())
80
+ onMounted(fetchNext);
81
+
82
+ watch(podcasts, async () => {
83
+ podcasts.value.forEach(async (podcast) => {
84
+ if (!tags.has(podcast.podcastId)) {
85
+ const t = await tagsFor(podcast);
86
+ tags.set(podcast.podcastId, t);
87
+ }
88
+ });
89
+ });
76
90
 
77
91
  //Methods
78
92
  async function fetchNext(): Promise<void> {
79
- loading.value = true;
80
- try {
81
- // Retrieve latest emissions
82
- const emissions = await classicApi.fetchData<ListClassicReturn<Emission>>({
83
- api: 0,
84
- path: "emission/search",
85
- parameters: {
86
- first: 0,
87
- size: 5,
88
- organisationId: props.organisationId,
89
- sort: "LAST_PODCAST_DESC",
90
- rubriqueId: props.rubriquesId
91
- },
92
- specialTreatement: true,
93
- });
93
+ loading.value = true;
94
+ try {
95
+ // Retrieve latest emissions
96
+ const emissions = await classicApi.fetchData<ListClassicReturn<Emission>>({
97
+ api: 0,
98
+ path: "emission/search",
99
+ parameters: {
100
+ first: 0,
101
+ size: 5,
102
+ organisationId: props.organisationId,
103
+ sort: "LAST_PODCAST_DESC",
104
+ rubriqueId: props.rubriquesId
105
+ },
106
+ specialTreatement: true,
107
+ });
94
108
 
95
- const promises: Array<Promise<SimplifiedPodcast>> = [];
109
+ const promises: Array<Promise<SimplifiedPodcast>> = [];
96
110
 
97
- for (let i = 0; i < emissions.result.length; i++) {
98
- promises.push(podcastApi.search({
99
- first: 0,
100
- size: 1,
101
- organisationId: [props.organisationId],
102
- emissionId: [emissions.result[i].emissionId],
103
- sort: PodcastSort.DATE,
104
- rubriqueId: props.rubriquesId
105
- }).then(r => r.result[0]));
106
- }
111
+ for (let i = 0; i < emissions.result.length; i++) {
112
+ promises.push(podcastApi.search({
113
+ first: 0,
114
+ size: 1,
115
+ organisationId: [props.organisationId],
116
+ emissionId: [emissions.result[i].emissionId],
117
+ sort: PodcastSort.DATE,
118
+ rubriqueId: props.rubriquesId
119
+ }).then(r => r.result[0]));
120
+ }
107
121
 
108
- // Retrieve the podcasts for these emissions
109
- const data = await Promise.all(promises);
122
+ // Retrieve the podcasts for these emissions
123
+ const data = await Promise.all(promises);
110
124
 
111
- podcasts.value = podcasts.value.concat(
112
- data.filter((em: SimplifiedPodcast | null) => null !== em && undefined !== em).map(p => {
113
- // Get emission from podcast
114
- const emission = emissions.result.find(e => e.emissionId === p.emissionId);
115
- // Create full podcast from simplified + emission
116
- return simplifiedToFull(p, emission.orga, emission);
117
- })
118
- );
125
+ podcasts.value = podcasts.value.concat(
126
+ data.filter((em: SimplifiedPodcast | null) => null !== em && undefined !== em).map(p => {
127
+ // Get emission from podcast
128
+ const emission = emissions.result.find(e => e.emissionId === p.emissionId);
129
+ // Create full podcast from simplified + emission
130
+ return simplifiedToFull(p, emission.orga, emission);
131
+ })
132
+ );
119
133
 
120
- // Sort podcasts by pub date so that the most recent one is focused
121
- podcasts.value.sort((p1, p2) => {
122
- return new Date(p2.pubDate).getTime() - new Date(p1.pubDate).getTime();
123
- });
134
+ // Sort podcasts by pub date so that the most recent one is focused
135
+ podcasts.value.sort((p1, p2) => {
136
+ return new Date(p2.pubDate).getTime() - new Date(p1.pubDate).getTime();
137
+ });
124
138
 
139
+ loading.value = false;
140
+ } catch (errorWs) {
141
+ console.error(errorWs);
142
+ handle403(errorWs as AxiosError);
143
+ error.value = true;
144
+ }
125
145
  loading.value = false;
126
- } catch (errorWs) {
127
- console.error(errorWs);
128
- handle403(errorWs as AxiosError);
129
- error.value = true;
130
- }
131
- loading.value = false;
132
146
  }
133
147
 
134
148
  function route(podcast: Podcast): RouteLocationRaw {
135
- return {
136
- name: 'podcast',
137
- params: { podcastId: podcast.podcastId }
138
- }
149
+ return {
150
+ name: 'podcast',
151
+ params: { podcastId: podcast.podcastId }
152
+ }
139
153
  }
140
154
  </script>