@saooti/octopus-sdk 41.1.3 → 41.1.5
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 +14 -0
- package/index.ts +4 -0
- package/package.json +2 -2
- package/src/api/apiUtils.ts +25 -0
- package/src/api/emissionApi.ts +31 -0
- package/src/api/organisationApi.ts +31 -0
- package/src/api/playlistApi.ts +72 -0
- package/src/components/display/playlist/PodcastList.vue +3 -5
- package/src/components/display/playlist/PodcastPlaylistInlineList.vue +12 -8
- package/src/components/display/podcasts/PodcastItem.vue +5 -5
- package/src/stores/class/general/podcast.ts +66 -25
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 41.1.5 (10/12/2025)
|
|
4
|
+
|
|
5
|
+
**Misc**
|
|
6
|
+
|
|
7
|
+
- Ajout API playlist, emission, et organisation
|
|
8
|
+
|
|
9
|
+
## 41.1.4 (04/12/2025)
|
|
10
|
+
|
|
11
|
+
**Misc**
|
|
12
|
+
|
|
13
|
+
- Passage de `pinia` à version `>=2.3.0`
|
|
14
|
+
- *Podcastmaker* utilise la version `^2.3.0`
|
|
15
|
+
- *Frontoffice* utilise la version `^3.0.3`
|
|
16
|
+
|
|
3
17
|
## 41.1.3 (04/12/2025)
|
|
4
18
|
|
|
5
19
|
**Misc**
|
package/index.ts
CHANGED
|
@@ -137,6 +137,10 @@ import {useAuthStore} from "./src/stores/AuthStore.ts";
|
|
|
137
137
|
import {getApiUrl, ModuleApi} from "./src/api/apiConnection.ts";
|
|
138
138
|
import classicApi from "./src/api/classicApi.ts";
|
|
139
139
|
|
|
140
|
+
export { emissionApi } from "./src/api/emissionApi.ts";
|
|
141
|
+
export { organisationApi } from "./src/api/organisationApi.ts";
|
|
142
|
+
export { playlistApi } from "./src/api/playlistApi.ts";
|
|
143
|
+
|
|
140
144
|
//Icons
|
|
141
145
|
export const getAmazonMusicIcon = () => import("./src/components/icons/AmazonMusicIcon.vue");
|
|
142
146
|
export const getApplePodcastIcon = () => import("./src/components/icons/ApplePodcastIcon.vue");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saooti/octopus-sdk",
|
|
3
|
-
"version": "41.1.
|
|
3
|
+
"version": "41.1.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Javascript SDK for using octopus",
|
|
6
6
|
"author": "Saooti",
|
|
@@ -89,6 +89,6 @@
|
|
|
89
89
|
"url": "git+https://github.com/saooti/octopus-sdk.git"
|
|
90
90
|
},
|
|
91
91
|
"peerDependencies": {
|
|
92
|
-
"pinia": "
|
|
92
|
+
"pinia": ">=2.3.0"
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility function to easily convert a list of IDs to a map of id => element
|
|
3
|
+
* @param ID The type of ID for the element
|
|
4
|
+
* @param T The type of element to retrieve
|
|
5
|
+
* @param ids The list of ids
|
|
6
|
+
* @param getter A function that given an ID, returns a promise of the matching element
|
|
7
|
+
* @param key The key for the ID
|
|
8
|
+
* @return A promise containing a map of ID => element
|
|
9
|
+
*/
|
|
10
|
+
export async function mapFromGetAll<ID extends string|number, T extends object >(ids: Array<ID>, getter: (id: ID) => Promise<T>, key: keyof T): Promise<Record<string, T>> {
|
|
11
|
+
const results: Record<string, T> = {};
|
|
12
|
+
const promises: Array<Promise<T>> = [];
|
|
13
|
+
|
|
14
|
+
// Retrieve data for each id
|
|
15
|
+
ids.forEach((id: ID) => {
|
|
16
|
+
const promise = getter(id).then(elt => results['' + elt[key]] = elt);
|
|
17
|
+
promises.push(promise);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Wait for all promises to finish
|
|
21
|
+
await Promise.all(promises);
|
|
22
|
+
|
|
23
|
+
return results;
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import classicApi from "./classicApi";
|
|
2
|
+
import { ModuleApi } from "./apiConnection";
|
|
3
|
+
import { mapFromGetAll } from "./apiUtils";
|
|
4
|
+
import { Emission } from "@/stores/class/general/emission";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Retrieve an emission by ID
|
|
8
|
+
* @param emissionId The ID of the emission
|
|
9
|
+
* @return An emission
|
|
10
|
+
*/
|
|
11
|
+
async function get(emissionId: number): Promise<Emission> {
|
|
12
|
+
return classicApi.fetchData<Emission>({
|
|
13
|
+
api: ModuleApi.DEFAULT,
|
|
14
|
+
path: 'emission/' + emissionId
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Retrieve all emissions specified by their IDs
|
|
20
|
+
* @param emissionIds A list of emission IDs. For better result, they
|
|
21
|
+
should be unique.
|
|
22
|
+
* @return The matching emissions
|
|
23
|
+
*/
|
|
24
|
+
async function getAllById(emissionIds: Array<number>): Promise<Record<string, Emission>> {
|
|
25
|
+
return mapFromGetAll(emissionIds, get, 'emissionId');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const emissionApi = {
|
|
29
|
+
get,
|
|
30
|
+
getAllById
|
|
31
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import classicApi from "./classicApi";
|
|
2
|
+
import { ModuleApi } from "./apiConnection";
|
|
3
|
+
import { Organisation } from "../stores/class/general/organisation";
|
|
4
|
+
import { mapFromGetAll } from "./apiUtils";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Retrieve an organisation by ID
|
|
8
|
+
* @param organisationId The ID of the organisation
|
|
9
|
+
* @return An organisation
|
|
10
|
+
*/
|
|
11
|
+
async function get(organisationId: string): Promise<Organisation> {
|
|
12
|
+
return classicApi.fetchData<Organisation>({
|
|
13
|
+
api: ModuleApi.DEFAULT,
|
|
14
|
+
path: 'organisation/' + organisationId
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Retrieve all organisations specified by their IDs
|
|
20
|
+
* @param organisationIds A list of organisation IDs. For better result, they
|
|
21
|
+
should be unique.
|
|
22
|
+
* @return The matching organisations
|
|
23
|
+
*/
|
|
24
|
+
async function getAllById(organisationIds: Array<string>): Promise<Record<string, Organisation>> {
|
|
25
|
+
return mapFromGetAll(organisationIds, get, 'id');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const organisationApi = {
|
|
29
|
+
get,
|
|
30
|
+
getAllById
|
|
31
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import classicApi from "./classicApi";
|
|
2
|
+
import { ModuleApi } from "./apiConnection";
|
|
3
|
+
import { Podcast, SimplifiedPodcast } from "../stores/class/general/podcast";
|
|
4
|
+
import { Playlist } from "../stores/class/general/playlist";
|
|
5
|
+
import { organisationApi } from "./organisationApi";
|
|
6
|
+
import { emissionApi } from "./emissionApi";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Retrieve playlist data
|
|
10
|
+
* @param playlistId The ID of the playlist
|
|
11
|
+
* @return The playlist
|
|
12
|
+
*/
|
|
13
|
+
async function get(playlistId: number): Promise<Playlist> {
|
|
14
|
+
return classicApi.fetchData<Playlist>({
|
|
15
|
+
api: ModuleApi.DEFAULT,
|
|
16
|
+
path: 'playlist/' + playlistId
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Retrieve the podcasts defined in the playlist
|
|
22
|
+
* @param playlistId The ID of the playlist
|
|
23
|
+
* @return A list of simplified podcasts
|
|
24
|
+
*/
|
|
25
|
+
async function getContent(playlistId: number): Promise<Array<SimplifiedPodcast>> {
|
|
26
|
+
return classicApi.fetchData<Array<SimplifiedPodcast>>({
|
|
27
|
+
api: ModuleApi.DEFAULT,
|
|
28
|
+
path: 'v2/playlist/' + playlistId + '/content'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Retrieve the podcasts defined in the playlist, with all their data
|
|
34
|
+
* This query is longer, because it also needs to retrieve organisations &
|
|
35
|
+
* emissions.
|
|
36
|
+
* @param playlistId The ID of the playlist
|
|
37
|
+
* @return A list of podcasts
|
|
38
|
+
*/
|
|
39
|
+
async function getContentFull(playlistId: number): Promise<Array<Podcast>> {
|
|
40
|
+
const simplified = await this.getContent(playlistId);
|
|
41
|
+
const full: Array<Podcast> = [];
|
|
42
|
+
|
|
43
|
+
// TODO unique
|
|
44
|
+
const organisationIds = simplified.map((p: SimplifiedPodcast) => p.organisationId);
|
|
45
|
+
// TODO unique
|
|
46
|
+
const emissionIds = simplified.map((p: SimplifiedPodcast) => p.emissionId);
|
|
47
|
+
|
|
48
|
+
const organisations = await organisationApi.getAllById(organisationIds);
|
|
49
|
+
const emissions = await emissionApi.getAllById(emissionIds);
|
|
50
|
+
|
|
51
|
+
simplified.forEach((s: SimplifiedPodcast) => {
|
|
52
|
+
const organisation = organisations[s.organisationId];
|
|
53
|
+
const emission = emissions[s.emissionId];
|
|
54
|
+
|
|
55
|
+
full.push({
|
|
56
|
+
...s,
|
|
57
|
+
organisation,
|
|
58
|
+
emission
|
|
59
|
+
});
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return full;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* API to manage playlists
|
|
67
|
+
*/
|
|
68
|
+
export const playlistApi = {
|
|
69
|
+
get,
|
|
70
|
+
getContent,
|
|
71
|
+
getContentFull
|
|
72
|
+
}
|
|
@@ -80,6 +80,7 @@ import { Playlist } from "@/stores/class/general/playlist";
|
|
|
80
80
|
import { computed, onBeforeMount, Ref, ref, watch } from "vue";
|
|
81
81
|
import { AxiosError } from "axios";
|
|
82
82
|
import { useI18n } from "vue-i18n";
|
|
83
|
+
import { playlistApi } from "../../../api/playlistApi";
|
|
83
84
|
|
|
84
85
|
//Props
|
|
85
86
|
const props = defineProps({
|
|
@@ -137,7 +138,7 @@ watch(searchPattern,() => {
|
|
|
137
138
|
}
|
|
138
139
|
});
|
|
139
140
|
|
|
140
|
-
onBeforeMount(
|
|
141
|
+
onBeforeMount(fetchContent);
|
|
141
142
|
|
|
142
143
|
|
|
143
144
|
//Methods
|
|
@@ -146,10 +147,7 @@ async function fetchContent(): Promise<void> {
|
|
|
146
147
|
podcasts.value.length = 0;
|
|
147
148
|
loading.value = true;
|
|
148
149
|
try {
|
|
149
|
-
podcasts.value = await
|
|
150
|
-
api: 0,
|
|
151
|
-
path: "playlist/" + props.playlist.playlistId + "/content",
|
|
152
|
-
});
|
|
150
|
+
podcasts.value = await playlistApi.getContentFull(props.playlist.playlistId);
|
|
153
151
|
if (!editRight.value) {
|
|
154
152
|
podcasts.value = podcasts.value.filter((p: Podcast | null) => {
|
|
155
153
|
return (
|
|
@@ -40,6 +40,7 @@ import { Podcast } from "@/stores/class/general/podcast";
|
|
|
40
40
|
import { Playlist } from "@/stores/class/general/playlist";
|
|
41
41
|
import { onMounted, Ref, ref, watch } from "vue";
|
|
42
42
|
import { useI18n } from "vue-i18n";
|
|
43
|
+
import { playlistApi } from "../../../api/playlistApi";
|
|
43
44
|
|
|
44
45
|
//Props
|
|
45
46
|
const props = defineProps<{
|
|
@@ -72,14 +73,17 @@ onMounted(()=>fetchContent())
|
|
|
72
73
|
async function fetchContent(): Promise<void> {
|
|
73
74
|
allPodcasts.value.length = 0;
|
|
74
75
|
loading.value = true;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
|
|
77
|
+
// Retrieve both playlist & content at the same time
|
|
78
|
+
const [playlistData, content] = await Promise.all([
|
|
79
|
+
playlistApi.get(props.playlistId),
|
|
80
|
+
playlistApi.getContentFull(props.playlistId)
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
// Update data
|
|
84
|
+
playlist.value = playlistData;
|
|
85
|
+
allPodcasts.value = content;
|
|
86
|
+
|
|
83
87
|
if (
|
|
84
88
|
!(
|
|
85
89
|
(undefined !== authStore.authOrgaId &&
|
|
@@ -42,15 +42,15 @@ import debounce from '../../../helper/debounceHelper';
|
|
|
42
42
|
import PodcastItemInfo from "./PodcastItemInfo.vue";
|
|
43
43
|
import PodcastImage from "./PodcastImage.vue";
|
|
44
44
|
import dayjs from "dayjs";
|
|
45
|
-
import { Podcast } from "
|
|
45
|
+
import { Podcast } from "../../../stores/class/general/podcast";
|
|
46
46
|
import { computed, nextTick, onBeforeMount, ref, Ref, useTemplateRef } from "vue";
|
|
47
47
|
import { Conference } from "@/stores/class/conference/conference";
|
|
48
48
|
|
|
49
49
|
//Props
|
|
50
|
-
const props = defineProps
|
|
51
|
-
podcast:
|
|
52
|
-
fetchConference
|
|
53
|
-
});
|
|
50
|
+
const props = defineProps<{
|
|
51
|
+
podcast: Podcast;
|
|
52
|
+
fetchConference?: Conference;
|
|
53
|
+
}>();
|
|
54
54
|
|
|
55
55
|
//Data
|
|
56
56
|
const isMobile = ref(false);
|
|
@@ -17,54 +17,95 @@ export enum ProcessingStatus {
|
|
|
17
17
|
All = "ALL"
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/** Describe the availability of the podcast */
|
|
21
|
+
export interface PodcastAvailability {
|
|
22
|
+
date?: number | null;
|
|
23
|
+
visibility?: boolean;
|
|
24
|
+
immediate?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
/**
|
|
21
28
|
* Data about a podcast/episode
|
|
22
29
|
*/
|
|
23
|
-
export interface Podcast {
|
|
30
|
+
export interface Podcast extends BasePodcast {
|
|
31
|
+
/** ID of the podcast */
|
|
32
|
+
podcastId: number;
|
|
33
|
+
/** Emission the podcast belongs to */
|
|
34
|
+
emission: Emission;
|
|
35
|
+
/** Organisation the podcast belongs to */
|
|
36
|
+
organisation: Organisation;
|
|
37
|
+
/** URL to the image */
|
|
24
38
|
imageUrl?: string;
|
|
25
|
-
|
|
26
|
-
annotations?: { [key: string]: string | number | boolean | undefined };
|
|
27
|
-
audioStorageUrl: string;
|
|
39
|
+
/** URL to the audio file (for downloading) */
|
|
28
40
|
audioUrl: string;
|
|
41
|
+
/** URL to the audio file (file on bucket) */
|
|
42
|
+
audioStorageUrl: string;
|
|
43
|
+
/** Title of the podcast */
|
|
44
|
+
title: string;
|
|
45
|
+
/** The availability of the podcast */
|
|
46
|
+
availability: PodcastAvailability;
|
|
47
|
+
/** Description of the podcast */
|
|
48
|
+
description?: string;
|
|
49
|
+
/** Publishing date */
|
|
50
|
+
pubDate?: string;
|
|
51
|
+
/** The status of the processing of the audio file */
|
|
52
|
+
processingStatus?: ProcessingStatus;
|
|
53
|
+
/** An optional list of tags */
|
|
54
|
+
tags?: Array<string>;
|
|
55
|
+
/** An optional list of tags for OuestFrance */
|
|
56
|
+
ofTags?: Array<string>;
|
|
57
|
+
|
|
58
|
+
createdAt?: string;
|
|
59
|
+
createdByUserId?: string;
|
|
60
|
+
annotations?: { [key: string]: string | number | boolean | undefined };
|
|
29
61
|
article?: string;
|
|
30
|
-
availability: {
|
|
31
|
-
date?: number | null;
|
|
32
|
-
visibility?: boolean;
|
|
33
|
-
immediate?: boolean;
|
|
34
|
-
};
|
|
35
62
|
comments?: string;
|
|
36
63
|
conferenceId?: number;
|
|
37
|
-
createdAt?: string;
|
|
38
|
-
createdByUserId?: string;
|
|
39
64
|
valid?: boolean;
|
|
40
|
-
description?: string;
|
|
41
65
|
downloadCount?: number;
|
|
66
|
+
weekDownloadCount?: number;
|
|
42
67
|
duration: number;
|
|
43
68
|
email?: string;
|
|
44
|
-
emission: Emission;
|
|
45
|
-
guests?: Array<Participant>;
|
|
46
69
|
monetisable?: string;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
processingStatus?: ProcessingStatus;
|
|
70
|
+
|
|
71
|
+
animators?: Array<Participant>;
|
|
72
|
+
guests?: Array<Participant>;
|
|
51
73
|
processorId?: string;
|
|
52
|
-
pubDate?: string;
|
|
53
74
|
publisher?: Person;
|
|
54
75
|
rubriqueIds?: Array<number>;
|
|
55
76
|
rssEpisode?:string;
|
|
56
77
|
score?: number;
|
|
57
78
|
size?: number;
|
|
58
|
-
/** An optional list of tags */
|
|
59
|
-
tags?: Array<string>;
|
|
60
|
-
/** An optional list of tags for OuestFrance */
|
|
61
|
-
ofTags?: Array<string>;
|
|
62
|
-
title: string;
|
|
63
|
-
weekDownloadCount?: number;
|
|
64
79
|
order?: number;
|
|
65
80
|
video?: Video;
|
|
66
81
|
}
|
|
67
82
|
|
|
83
|
+
/**
|
|
84
|
+
* A podcast with incomplete data
|
|
85
|
+
*/
|
|
86
|
+
export interface SimplifiedPodcast extends
|
|
87
|
+
Omit<Podcast, 'emission'|'organisation'|'animators'|'guests'|'ofTags'|'comments'|'email'|'processorId'|'publisher'|'order'|'video'> {
|
|
88
|
+
|
|
89
|
+
/** The ID of the emission */
|
|
90
|
+
emissionId: number;
|
|
91
|
+
/** The ID of the organisation */
|
|
92
|
+
organisationId: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Convert a simplified podcast to a complete one
|
|
97
|
+
* @param simplified The incomplete podcast
|
|
98
|
+
* @param organisation The organisation the podcast belongs to
|
|
99
|
+
* @param emission The emission the podcast belongs to
|
|
100
|
+
*/
|
|
101
|
+
export function simplifiedToFull(simplified: SimplifiedPodcast, organisation: Organisation, emission: Emission): Podcast {
|
|
102
|
+
return {
|
|
103
|
+
...simplified,
|
|
104
|
+
organisation,
|
|
105
|
+
emission
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
68
109
|
export function emptyPodcastData(): Podcast {
|
|
69
110
|
return {
|
|
70
111
|
podcastId: 0,
|