@saooti/octopus-sdk 41.5.4 → 41.5.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 CHANGED
@@ -1,5 +1,18 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 41.5.5 (16/02/2026)
4
+
5
+ **Fix**
6
+
7
+ - Correctif pour la lecture de lives/radio sur Organisation sécurisée sous
8
+ chrome
9
+ - Correction affichage critère de filtrage pour épisodes à valider
10
+
11
+ **Misc**
12
+
13
+ - Ajout de `frameborder="0"` dans les iframes miniplayer
14
+ - Ajustements de composants génériques
15
+
3
16
  ## 41.5.4 (12/02/2026)
4
17
 
5
18
  **Misc**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "41.5.4",
3
+ "version": "41.5.5",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -28,19 +28,23 @@ export const usePlayerLive = (hlsReady: Ref<boolean>)=>{
28
28
  return authStore.authParam.accessToken && ("SECURED" === playerStore.playerLive?.organisation?.privacy || playerStore.playerRadio?.secured);
29
29
  });
30
30
 
31
- function onPlay(): void {
31
+ function onPlay(): void {
32
32
  playerStore.playerChangeStatus(PlayerStatus.PAUSED ===playerStore.playerStatus);
33
33
  }
34
34
 
35
35
  function playRadio() {
36
- if (!playerStore.playerRadio) return;
36
+ if (!playerStore.playerRadio) {
37
+ return;
38
+ }
37
39
  handleSessionIdRadio();
38
40
  playerStore.playerUpdatePlayerHlsUrl(playerStore.playerRadio.url+"?origin=octopus&sessionId="+playerStore.playerRadio.sessionId);
39
41
  playHls();
40
42
  }
41
43
 
42
44
  function handleSessionIdRadio(){
43
- if(!playerStore.playerRadio) return;
45
+ if(!playerStore.playerRadio) {
46
+ return;
47
+ }
44
48
  if(playerStore.playerRadio.sessionId && dayjs().diff(dayjs(playerStore.playerRadio.dateSessionId), 'm')<maxMinutesSessionId){
45
49
  return;
46
50
  }
@@ -48,7 +52,9 @@ export const usePlayerLive = (hlsReady: Ref<boolean>)=>{
48
52
  }
49
53
 
50
54
  function playLive() {
51
- if (!playerStore.playerHlsIdentifier) return;
55
+ if (!playerStore.playerHlsIdentifier) {
56
+ return;
57
+ }
52
58
  playerStore.playerUpdatePlayerHlsUrl(`${apiStore.hlsUrl}live/${playerStore.playerHlsIdentifier}/index.m3u8`);
53
59
  playHls();
54
60
  }
@@ -74,11 +80,15 @@ export const usePlayerLive = (hlsReady: Ref<boolean>)=>{
74
80
  !isChrome &&
75
81
  !isAndroid
76
82
  ) {
83
+ let url = playerStore.playerHlsUrl;
77
84
  if(needToAddToken.value) {
78
- audioElement.value.src = playerStore.playerHlsUrl+"?access_token="+authStore.authParam.accessToken;
79
- }else{
80
- audioElement.value.src = playerStore.playerHlsUrl;
85
+ if (url.includes('?')) {
86
+ url += "&access_token="+authStore.authParam.accessToken;
87
+ } else {
88
+ url += "?access_token="+authStore.authParam.accessToken;
89
+ }
81
90
  }
91
+ audioElement.value.src = url;
82
92
  await initLiveDownloadId();
83
93
  hlsReady.value = true;
84
94
  await audioElement.value.play();
@@ -233,7 +233,7 @@ const isSelectValidity = computed(() => {
233
233
  undefined !== organisation.value &&
234
234
  organisationRight.value &&
235
235
  authStore.isRoleContribution &&
236
- !isPodcastmaker &&
236
+ !isPodcastmaker.value &&
237
237
  !props.isEmission &&
238
238
  props.includeHidden
239
239
  );
@@ -20,6 +20,7 @@
20
20
  allowfullscreen="true"
21
21
  allow="clipboard-read; clipboard-write; autoplay"
22
22
  referrerpolicy="no-referrer-when-downgrade"
23
+ frameborder="0"
23
24
  :src="iFrameSrc"
24
25
  width="100%"
25
26
  :height="iFrameHeight"
@@ -273,7 +274,7 @@ const iFrame = computed(() => {
273
274
  const specialDigiteka = props.podcast?.video?.videoId
274
275
  ? 'allowfullscreen="true" referrerpolicy="no-referrer-when-downgrade"'
275
276
  : "";
276
- return `<iframe src="${iFrameSrc.value}" width="100%" height="${iFrameHeight.value}" scrolling="no" ${specialDigiteka} allow="clipboard-read; clipboard-write; autoplay"></iframe>`;
277
+ return `<iframe src="${iFrameSrc.value}" width="100%" height="${iFrameHeight.value}" frameborder="0" scrolling="no" ${specialDigiteka} allow="clipboard-read; clipboard-write; autoplay"></iframe>`;
277
278
  });
278
279
  const dataTitle = computed(() => {
279
280
  if (props.podcast) return props.podcast.podcastId;
@@ -8,6 +8,7 @@
8
8
  id="miniplayerIframeRadio"
9
9
  title="Miniplayer"
10
10
  :src="iFrameSrc"
11
+ frameborder="0"
11
12
  width="100%"
12
13
  height="140px"
13
14
  style="overflow: hidden"
@@ -90,7 +91,7 @@ const iFrameSrc = computed(() => {
90
91
  return url;
91
92
  });
92
93
  const iFrame = computed(() => {
93
- return `<iframe src="${iFrameSrc.value}" width="100%" height="140px" scrolling="no" allow="clipboard-read; clipboard-write; autoplay"></iframe>`;
94
+ return `<iframe src="${iFrameSrc.value}" width="100%" height="140px" frameborder="0" scrolling="no" allow="clipboard-read; clipboard-write; autoplay"></iframe>`;
94
95
  });
95
96
 
96
97
 
@@ -82,7 +82,19 @@ const props = defineProps({
82
82
  })
83
83
 
84
84
  //Emits
85
- const emit = defineEmits(["updateDate", "update:date"]);
85
+ const emit = defineEmits<{
86
+ /**
87
+ * Update the date
88
+ * @param value The new date
89
+ * @deprecated
90
+ */
91
+ (e: "updateDate", value: Date): void;
92
+ /**
93
+ * Update the date
94
+ * @param value The new date
95
+ */
96
+ (e: "update:date", value: Date): void;
97
+ }>();
86
98
 
87
99
  //Data
88
100
  const divContainerRef = useTemplateRef('divContainer');
@@ -147,6 +159,7 @@ function updateValue(date: Date) {
147
159
  (divContainerRef?.value as HTMLElement)?.focus();
148
160
  }
149
161
  emit("updateDate", date);
162
+ emit("update:date", date);
150
163
  }
151
164
 
152
165
  function formatDate(value: Date): string {
@@ -4,8 +4,10 @@
4
4
  Available slots:
5
5
  `label-{option.value}`: Slot to replace the label of the current option.
6
6
  Binding: `option`: the current option
7
+ `selected` : true if the option is selected
7
8
  `after-{option.value}`: Slot after the radio button
8
9
  Binding: `option`: the current option
10
+ `selected` : true if the option is selected
9
11
  -->
10
12
  <template>
11
13
  <div role="radiogroup" class="d-flex" :class="isColumn ? 'flex-column' : ''">
@@ -33,20 +35,14 @@
33
35
  </div>
34
36
  </template>
35
37
 
36
- <script setup lang="ts">
37
-
38
- interface Option {
39
- title: string;
40
- value: string | undefined
41
- };
42
-
38
+ <script setup generic="T extends { title: string; value: string|undefined; }" lang="ts">
43
39
  //Props
44
40
  const { textInit } = defineProps({
45
41
  idRadio: { default: "", type: String },
46
42
  isDisabled: { default: false, type: Boolean },
47
43
  options: {
48
44
  default: () => [],
49
- type: Array as () => Array<Option>,
45
+ type: Array as () => Array<T>,
50
46
  },
51
47
  textInit: { default: undefined, type: String },
52
48
  isColumn: { default: true, type: Boolean },
@@ -60,11 +56,10 @@ function onChange(value:string){
60
56
  emit('update:textInit', value)
61
57
  }
62
58
 
63
- function slotBindings(option: Option): { option: Option; selected: boolean } {
59
+ function slotBindings(option: T): { option: T; selected: boolean } {
64
60
  return {
65
61
  option,
66
62
  selected: textInit === option.value
67
63
  }
68
64
  }
69
-
70
65
  </script>
@@ -0,0 +1,58 @@
1
+ import '@tests/mocks/useRouter';
2
+ import '@tests/mocks/i18n';
3
+
4
+ import SharePlayer from '@/components/display/sharing/SharePlayer.vue';
5
+ import { mount as testMount } from '@tests/utils';
6
+ import { describe, expect, it, vi } from 'vitest';
7
+ import { useApiStore } from '@/stores/ApiStore';
8
+ import { useSaveFetchStore } from '@/stores/SaveFetchStore';
9
+
10
+ describe('SharePlayer', () => {
11
+ it('renders iframe with frameborder="0"', async () => {
12
+ const wrapper = await testMount(SharePlayer, {
13
+ props: {
14
+ podcast: {
15
+ podcastId: 123,
16
+ organisation: { id: 'org1' },
17
+ availability: { visibility: true }
18
+ },
19
+ organisationId: 'org1',
20
+ notExclusive: true
21
+ },
22
+ beforeMount: async () => {
23
+ const apiStore = useApiStore();
24
+ apiStore.miniplayerUrl = 'https://test.com/';
25
+
26
+ const saveFetchStore = useSaveFetchStore();
27
+ vi.spyOn(saveFetchStore, 'getOrgaAttributes').mockResolvedValue({});
28
+ }
29
+ });
30
+
31
+ const iframe = wrapper.find('#miniplayerIframe');
32
+ expect(iframe.attributes('frameborder')).toBe('0');
33
+ });
34
+
35
+ it('includes frameborder="0" in generated iframe code', async () => {
36
+ const wrapper = await testMount(SharePlayer, {
37
+ props: {
38
+ podcast: {
39
+ podcastId: 123,
40
+ organisation: { id: 'org1' },
41
+ availability: { visibility: true }
42
+ },
43
+ organisationId: 'org1',
44
+ notExclusive: true
45
+ },
46
+ beforeMount: async () => {
47
+ const apiStore = useApiStore();
48
+ apiStore.miniplayerUrl = 'https://test.com/';
49
+
50
+ const saveFetchStore = useSaveFetchStore();
51
+ vi.spyOn(saveFetchStore, 'getOrgaAttributes').mockResolvedValue({});
52
+ }
53
+ });
54
+
55
+ const iFrameCode = (wrapper.vm as any).iFrame;
56
+ expect(iFrameCode).toContain('frameborder="0"');
57
+ });
58
+ });
@@ -0,0 +1,54 @@
1
+ import '@tests/mocks/useRouter';
2
+ import '@tests/mocks/i18n';
3
+
4
+ import SharePlayerRadio from '@/components/display/sharing/SharePlayerRadio.vue';
5
+ import { mount as testMount } from '@tests/utils';
6
+ import { describe, expect, it, vi } from 'vitest';
7
+ import { useApiStore } from '@/stores/ApiStore';
8
+ import { useSaveFetchStore } from '@/stores/SaveFetchStore';
9
+
10
+ describe('SharePlayerRadio', () => {
11
+ it('renders iframe with frameborder="0"', async () => {
12
+ const wrapper = await testMount(SharePlayerRadio, {
13
+ props: {
14
+ canal: {
15
+ id: 'radio1',
16
+ organisationId: 'org1'
17
+ },
18
+ organisationId: 'org1'
19
+ },
20
+ beforeMount: async () => {
21
+ const apiStore = useApiStore();
22
+ apiStore.miniplayerUrl = 'https://test.com/';
23
+
24
+ const saveFetchStore = useSaveFetchStore();
25
+ vi.spyOn(saveFetchStore, 'getOrgaAttributes').mockResolvedValue({});
26
+ }
27
+ });
28
+
29
+ const iframe = wrapper.find('#miniplayerIframeRadio');
30
+ expect(iframe.attributes('frameborder')).toBe('0');
31
+ });
32
+
33
+ it('includes frameborder="0" in generated iframe code', async () => {
34
+ const wrapper = await testMount(SharePlayerRadio, {
35
+ props: {
36
+ canal: {
37
+ id: 'radio1',
38
+ organisationId: 'org1'
39
+ },
40
+ organisationId: 'org1'
41
+ },
42
+ beforeMount: async () => {
43
+ const apiStore = useApiStore();
44
+ apiStore.miniplayerUrl = 'https://test.com/';
45
+
46
+ const saveFetchStore = useSaveFetchStore();
47
+ vi.spyOn(saveFetchStore, 'getOrgaAttributes').mockResolvedValue({});
48
+ }
49
+ });
50
+
51
+ const iFrameCode = (wrapper.vm as any).iFrame;
52
+ expect(iFrameCode).toContain('frameborder="0"');
53
+ });
54
+ });