@saooti/octopus-sdk 40.2.8 → 40.2.10

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.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/src/App.vue +1 -1
  3. package/src/components/composable/player/usePlayerLogic.ts +17 -9
  4. package/src/components/composable/podcasts/usePodcastView.ts +12 -13
  5. package/src/components/composable/radio/usefetchRadioData.ts +1 -1
  6. package/src/components/composable/route/useAdvancedParamInit.ts +0 -1
  7. package/src/components/display/filter/AdvancedSearch.vue +19 -1
  8. package/src/components/display/podcasts/PodcastModuleBox.vue +1 -1
  9. package/src/components/display/podcasts/PodcastRawTranscript.vue +1 -5
  10. package/src/components/display/podcasts/PodcastRubriqueList.vue +1 -1
  11. package/src/components/display/podcasts/TagList.vue +7 -2
  12. package/src/components/display/rubriques/RubriqueList.vue +6 -1
  13. package/src/components/display/sharing/QrCode.vue +5 -5
  14. package/src/components/display/sharing/SharePlayerTypes.vue +6 -1
  15. package/src/components/form/ClassicDatePicker.vue +0 -1
  16. package/src/components/form/ClassicLoading.vue +1 -1
  17. package/src/components/form/ClassicSelect.vue +6 -1
  18. package/src/components/misc/ClassicPopover.vue +40 -30
  19. package/src/components/misc/ClassicSpinner.vue +86 -2
  20. package/src/components/misc/ProgressBar.vue +69 -4
  21. package/src/components/misc/TopBarMainContent.vue +5 -2
  22. package/src/components/misc/player/ads/AdsProgressBar.vue +8 -15
  23. package/src/components/misc/player/radio/RadioProgressBar.vue +8 -22
  24. package/src/components/misc/player/video/PlayerVideo.vue +13 -5
  25. package/src/components/misc/player/video/PlayerYoutubeEmbed.vue +29 -0
  26. package/src/components/pages/PodcastPage.vue +6 -1
  27. package/src/helper/youtubeVideoHelper.ts +13 -0
  28. package/src/stores/CommentStore.ts +1 -2
  29. package/src/style/general.scss +0 -13
  30. package/src/style/share.scss +36 -2
  31. package/src/style/progressbar.scss +0 -77
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "40.2.8",
3
+ "version": "40.2.10",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
package/src/App.vue CHANGED
@@ -40,7 +40,7 @@ export default defineComponent({
40
40
  CategoryFilter,
41
41
  FooterOctopus,
42
42
  PlayerComponent,
43
- ClassicLazy,
43
+ ClassicLazy
44
44
  },
45
45
 
46
46
  setup(){
@@ -7,6 +7,7 @@ import { usePlayerStore } from "../../../stores/PlayerStore";
7
7
  import { useAuthStore } from "../../../stores/AuthStore";
8
8
  import { useGeneralStore } from "../../../stores/GeneralStore";
9
9
  import { useVastStore } from "../../../stores/VastStore";
10
+ import fetchHelper from "../../../helper/fetchHelper";
10
11
  import classicApi from "../../../api/classicApi";
11
12
  import dayjs from "dayjs";
12
13
  import { FetchParam } from "@/stores/class/general/fetchParam";
@@ -98,19 +99,26 @@ export const usePlayerLogic = (forceHide: Ref<boolean, boolean>)=>{
98
99
  } else if ("PAUSED" === playerStore.playerStatus) {
99
100
  audioPlayer.pause();
100
101
  } else if ("PLAYING" === playerStore.playerStatus && playerStore.playerRadio) {
101
- if (playerStore.playerRadio.isInit) {
102
- if(vastStore.isAdPlaying && !vastStore.resetSessionId){
103
- playerStore.playerRadio.dateSessionId = dayjs().toISOString();
104
- }
105
- playRadio();
106
- } else {
107
- playerStore.playerRadio.isInit = true;
108
- }
102
+ handlePlayRadio();
109
103
  } else if ("PLAYING" === playerStore.playerStatus) {
110
104
  audioPlayer.play();
111
105
  }
112
106
  });
113
107
 
108
+ function handlePlayRadio(){
109
+ if(!playerStore.playerRadio){
110
+ return;
111
+ }
112
+ if (playerStore.playerRadio.isInit) {
113
+ if(vastStore.isAdPlaying && !vastStore.resetSessionId){
114
+ playerStore.playerRadio.dateSessionId = dayjs().toISOString();
115
+ }
116
+ playRadio();
117
+ } else {
118
+ playerStore.playerRadio.isInit = true;
119
+ }
120
+ }
121
+
114
122
  function getAudioUrlParameters(): FetchParam {
115
123
  if (!playerStore.playerPodcast) return {};
116
124
  const parameters: FetchParam = {
@@ -143,7 +151,7 @@ export const usePlayerLogic = (forceHide: Ref<boolean, boolean>)=>{
143
151
  )
144
152
  return playerStore.playerPodcast.audioStorageUrl;
145
153
  if (listenError.value) return playerStore.playerPodcast.audioStorageUrl;
146
- return playerStore.playerPodcast.podcastId + ".mp3?"+getAudioUrlParameters().toString();
154
+ return playerStore.playerPodcast.podcastId + ".mp3?"+fetchHelper.getUriSearchParams(getAudioUrlParameters());
147
155
  }
148
156
 
149
157
  function reInitPlayer(): void {
@@ -20,8 +20,7 @@ export const usePodcastView = (podcast: Ref<Podcast|undefined>, podcastConferen
20
20
  });
21
21
  const isLiveReadyToRecord = computed(() => {
22
22
  return (
23
- undefined !== podcast.value &&
24
- undefined !== podcast.value.conferenceId &&
23
+ undefined !== podcast.value?.conferenceId &&
25
24
  0 !== podcast.value.conferenceId &&
26
25
  "READY_TO_RECORD" === podcast.value.processingStatus
27
26
  );
@@ -52,24 +51,24 @@ export const usePodcastView = (podcast: Ref<Podcast|undefined>, podcastConferen
52
51
  });
53
52
 
54
53
  const duration = computed(() => {
55
- if (!podcast.value || podcast.value.duration <= 1) return "";
56
- if (podcast.value.duration > 600000) {
57
- return humanizeDuration(podcast.value.duration, {
58
- language: i18n.locale.value,
59
- largest: 1,
60
- round: true,
61
- });
62
- }
54
+ if (!podcast.value || podcast.value.duration <= 1){return ""};
55
+ if (podcast.value.duration > 600000) {
63
56
  return humanizeDuration(podcast.value.duration, {
64
57
  language: i18n.locale.value,
65
- largest: 2,
58
+ largest: 1,
66
59
  round: true,
67
60
  });
61
+ }
62
+ return humanizeDuration(podcast.value.duration, {
63
+ language: i18n.locale.value,
64
+ largest: 2,
65
+ round: true,
66
+ });
68
67
  });
69
68
 
70
69
  const durationIso = computed(() => {
71
- if (!podcast.value || podcast.value.duration <= 1) return "";
72
- return dayjs.duration({ milliseconds: podcast.value.duration }).toISOString();
70
+ if (!podcast.value || podcast.value.duration <= 1){return "";}
71
+ return dayjs.duration({ milliseconds: podcast.value.duration }).toISOString();
73
72
  });
74
73
  return {
75
74
  isLiveReadyToRecord,
@@ -24,7 +24,7 @@ export const useFetchRadio = ()=>{
24
24
  api: 14,
25
25
  path: "player/playing/" + canalId,
26
26
  });
27
- /* metadata.nextAdvertising={
27
+ /*{
28
28
  "adCount": 1,
29
29
  "startDate": "2025-03-04T13:12:00Z",
30
30
  "tag": "5e385e1b51c86"
@@ -64,7 +64,6 @@ export const useAdvancedParamInit = (props: any, isEmission: boolean)=>{
64
64
  if (!isInit.value) {
65
65
  return;
66
66
  }
67
- // TODO si oldValue !=null
68
67
  rubriqueFilter.value = [];
69
68
  });
70
69
 
@@ -7,6 +7,7 @@
7
7
  <div>{{ $t("Advanced filters") }}</div>
8
8
  <ChevronDownIcon :class="{ 'arrow-transform': showFilters }" />
9
9
  </button>
10
+ <Transition name="advanced-search">
10
11
  <div
11
12
  v-if="firstLoaded"
12
13
  v-show="showFilters"
@@ -76,6 +77,7 @@
76
77
  @update:sort="updateSort"
77
78
  />
78
79
  </div>
80
+ </Transition>
79
81
  </div>
80
82
  </template>
81
83
 
@@ -282,12 +284,28 @@ export default defineComponent({
282
284
  background: var(--octopus-background);
283
285
  display: flex;
284
286
  width: 100%;
285
- margin-bottom: 1rem;
287
+ padding-bottom: 1rem;
286
288
  justify-content: space-around;
287
289
 
288
290
  @media (width <= 720px) {
289
291
  flex-wrap: wrap;
290
292
  }
291
293
  }
294
+
295
+ .advanced-search-enter-active,
296
+ .advanced-search-leave-active {
297
+ transition: 0.3s all;
298
+ opacity: 1;
299
+ max-height: 900px;
300
+ height: auto;
301
+ overflow: hidden;
302
+ }
303
+
304
+ .advanced-search-enter-from,
305
+ .advanced-search-leave-to {
306
+ opacity: 0;
307
+ max-height: 0;
308
+ overflow: hidden;
309
+ }
292
310
  }
293
311
  </style>
@@ -40,7 +40,7 @@
40
40
  <div v-if="isLiveReady" class="text-danger">
41
41
  {{ $t("Episode record in live") }}
42
42
  </div>
43
- <div class="d-flex flex-column align-items-end flex-grow-1">
43
+ <div class="d-flex flex-column align-items-end">
44
44
  <time :datetime="durationIso">
45
45
  {{ duration }}
46
46
  </time>
@@ -146,6 +146,7 @@ export default defineComponent({
146
146
 
147
147
  &.open{
148
148
  margin-left:auto;
149
+ direction: rtl;
149
150
  @media (width <= 625px) {
150
151
  margin-top: 0.5rem;
151
152
  }
@@ -179,11 +180,6 @@ export default defineComponent({
179
180
  right: -30px;
180
181
  transform-origin: center left;
181
182
  }
182
-
183
- &.open {
184
- direction: rtl;
185
- }
186
-
187
183
  &:hover {
188
184
  text-indent: 30px;
189
185
  }
@@ -59,7 +59,7 @@ export default defineComponent({
59
59
  async fetchRubriquages(){
60
60
  const rubriquagesOrga = await this.getOrgaRubriques(this.orgaId);
61
61
  const rubriquesArray= rubriquagesOrga.flatMap((rub) =>rub.rubriques);
62
- this.rubriquagesOrga= rubriquesArray.reduce((results, u)=> (results[u.rubriqueId??0] = u, results), {} as {[key:number]:Rubrique});
62
+ this.rubriquagesOrga= rubriquesArray.reduce((results, u)=> {results[u.rubriqueId??0] = u; return results}, {} as {[key:number]:Rubrique});
63
63
  this.init = true;
64
64
  },
65
65
  }
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <div
3
- v-if="undefined !== tagList && 0 !== tagList.length"
3
+ v-if="undefined !== tagListFiltered && 0 !== tagListFiltered.length"
4
4
  class="tag-list-component d-flex align-items-center flex-wrap mb-3 small-text"
5
5
  >
6
6
  <div class="fw-bold me-3">
7
7
  {{ $t("Podcast tags") + " : " }}
8
8
  </div>
9
9
  <router-link
10
- v-for="(tag, index) in tagList"
10
+ v-for="(tag, index) in tagListFiltered"
11
11
  :key="tag"
12
12
  class="d-flex align-items-center border p-1 m-1 text-dark"
13
13
  :to="{
@@ -72,6 +72,11 @@ export default defineComponent({
72
72
  },
73
73
  computed: {
74
74
  ...mapState(useFilterStore, ["filterOrgaId"]),
75
+ tagListFiltered(): Array<string>{
76
+ return this.tagList.filter((tag: string) => {
77
+ return !tag.match(/^\[\[.*\]\]$/);
78
+ });
79
+ },
75
80
  organisationQuery(){
76
81
  if(this.filterOrgaId){
77
82
  return undefined;
@@ -107,7 +107,12 @@ export default defineComponent({
107
107
  return !rubriquageIdToNotShow.includes(element.rubriquageId);
108
108
  });
109
109
  }
110
- return Array.from(this.rubriquages).toSorted((a,b) => (a.title > b.title) ? 1 : ((b.title > a.title) ? -1 : 0));
110
+ return Array.from(this.rubriquages).toSorted((a,b) => {
111
+ if(a.title > b.title){
112
+ return 1;
113
+ }
114
+ return (b.title > a.title) ? -1 : 0;
115
+ });
111
116
  },
112
117
  },
113
118
  watch: {
@@ -25,7 +25,7 @@
25
25
  :margin="2"
26
26
  />
27
27
  <div class="d-flex align-items-center my-3">
28
- <FormatSwitch class="me-3" v-model:isSvg="isSvg"/>
28
+ <FormatSwitch v-model:is-svg="isSvg" class="me-3"/>
29
29
  <button class="btn btn-primary" @click="download">
30
30
  {{ $t("Download") }}
31
31
  </button>
@@ -78,11 +78,11 @@ export default defineComponent({
78
78
  if (!canvas || canvas.length <=0 || !canvas[0]) {
79
79
  return;
80
80
  }
81
- var downloadLink = document.createElement("a");
81
+ const downloadLink = document.createElement("a");
82
82
  if (this.isSvg) {
83
- var svgData = canvas[0].outerHTML;
84
- var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
85
- var svgUrl = URL.createObjectURL(svgBlob);
83
+ const svgData = canvas[0].outerHTML;
84
+ const svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
85
+ const svgUrl = URL.createObjectURL(svgBlob);
86
86
  downloadLink.href = svgUrl;
87
87
  downloadLink.download = "qrcode.svg";
88
88
  downloadLink.click();
@@ -119,7 +119,12 @@ export default defineComponent({
119
119
  !this.podcast) ||
120
120
  ("PLAYLIST" === player.typePlayer && this.playlist)
121
121
  );
122
- }).sort((a,b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0));
122
+ }).sort((a,b) => {
123
+ if(a.name > b.name){
124
+ return 1;
125
+ }
126
+ return (b.name > a.name) ? -1 : 0;
127
+ });
123
128
  },
124
129
  },
125
130
  created() {
@@ -1,6 +1,5 @@
1
1
  <template>
2
2
  <div ref="divContainer" tabindex="0">
3
-
4
3
  <label
5
4
  v-if="label && !range"
6
5
  class="form-label"
@@ -4,7 +4,7 @@
4
4
  class="d-flex align-items-center justify-content-center"
5
5
  >
6
6
  <ClassicSpinner class="me-3" />
7
- <div class="h3 mt-2">
7
+ <div class="h3">
8
8
  {{ loadingText }}
9
9
  </div>
10
10
  </div>
@@ -76,7 +76,12 @@ export default defineComponent({
76
76
  optionsOrder(){
77
77
  const optionsOrdered = Array.from(this.options);
78
78
  if(this.orderOptions){
79
- optionsOrdered.sort((a,b) => (a.title > b.title) ? 1 : ((b.title > a.title) ? -1 : 0));
79
+ optionsOrdered.sort((a,b) => {
80
+ if(a.title > b.title){
81
+ return 1;
82
+ }
83
+ return (b.title > a.title) ? -1 : 0
84
+ });
80
85
  }
81
86
  if(this.topOption){
82
87
  optionsOrdered.unshift(this.topOption);
@@ -153,23 +153,48 @@ export default defineComponent({
153
153
  this.targetElement.removeEventListener("focusout", this.clearDataBlur);
154
154
  }
155
155
  },
156
+ handleClickEvent(){
157
+ if (this.show && this.isClick) {
158
+ this.isClick = false;
159
+ this.clearData();
160
+ return -1;
161
+ }
162
+ if (this.show && this.isTopLayerPopover) {
163
+ (this.$refs.popover as HTMLElement).showPopover();
164
+ this.isClick = true;
165
+ return -1;
166
+ }
167
+ this.isClick = true;
168
+ return 0;
169
+ },
170
+ handleLeftPos(rectElement: DOMRect, parentLeft: number, sizeAvailable: number, sizePopover: number){
171
+ const elementRightRelative = rectElement.right - parentLeft;
172
+ const hasPlaceRightButton = (sizeAvailable - (sizeAvailable - elementRightRelative)) > sizePopover;
173
+ if(hasPlaceRightButton){
174
+ this.posX =
175
+ rectElement.right -
176
+ parentLeft -
177
+ sizePopover;
178
+ }else{
179
+ this.posX =parentLeft;
180
+ }
181
+ },
182
+ handleRightPos(rectElement: DOMRect, parentLeft: number, sizeAvailable: number, sizePopover: number){
183
+ const elementLeftRelative = rectElement.left - parentLeft;
184
+ const hasPlaceRightButton = (sizeAvailable - elementLeftRelative) > sizePopover;
185
+ if(hasPlaceRightButton){
186
+ this.posX = elementLeftRelative;
187
+ }else{
188
+ this.posX = sizeAvailable - sizePopover + parentLeft;
189
+ }
190
+ },
156
191
  setPopoverData(e: MouseEvent | PointerEvent) {
157
192
  clearInterval(this.clearTimeout as unknown as number);
158
193
  if (this.disable || !e || !e.target) {
159
194
  return;
160
195
  }
161
- if ("click" === e.type) {
162
- if (this.show && this.isClick) {
163
- this.isClick = false;
164
- this.clearData();
165
- return;
166
- }
167
- if (this.show && this.isTopLayerPopover) {
168
- (this.$refs.popover as HTMLElement).showPopover();
169
- this.isClick = true;
170
- return;
171
- }
172
- this.isClick = true;
196
+ if ("click" === e.type && -1 === this.handleClickEvent()) {
197
+ return;
173
198
  }
174
199
  this.show = true;
175
200
  let parentLeft = 0;
@@ -197,26 +222,11 @@ export default defineComponent({
197
222
  const rectElement = (e.target as HTMLElement).getBoundingClientRect();
198
223
  (this.$refs.popover as HTMLElement).style.display = "block";
199
224
  const sizePopover = (this.$refs.popover as HTMLElement).clientWidth;
200
- const sizeAvailable = parentWidth? parentWidth : window.innerWidth;
225
+ const sizeAvailable = parentWidth || window.innerWidth;
201
226
  if (this.leftPos) {
202
- const elementRightRelative = rectElement.right - parentLeft;
203
- const hasPlaceRightButton = (sizeAvailable - (sizeAvailable - elementRightRelative)) > sizePopover;
204
- if(hasPlaceRightButton){
205
- this.posX =
206
- rectElement.right -
207
- parentLeft -
208
- sizePopover;
209
- }else{
210
- this.posX =parentLeft;
211
- }
227
+ this.handleLeftPos(rectElement, parentLeft, sizeAvailable, sizePopover);
212
228
  } else {
213
- const elementLeftRelative = rectElement.left - parentLeft;
214
- const hasPlaceRightButton = (sizeAvailable - elementLeftRelative) > sizePopover;
215
- if(hasPlaceRightButton){
216
- this.posX = elementLeftRelative;
217
- }else{
218
- this.posX = sizeAvailable - sizePopover + parentLeft;
219
- }
229
+ this.handleRightPos(rectElement, parentLeft, sizeAvailable, sizePopover);
220
230
  }
221
231
  this.posX = Math.max(0, this.posX);
222
232
  const yPosParent = this.topPos ? rectElement.top : rectElement.bottom;
@@ -1,5 +1,7 @@
1
1
  <template>
2
- <div class="octopus-spinner" :class="small ? 'small' : ''" />
2
+ <div class="octopus-spinner" :style="small ? '--size-spinner:1rem;' : ''" >
3
+ <div v-for="index of 12" :key="index"></div>
4
+ </div>
3
5
  </template>
4
6
 
5
7
  <script lang="ts">
@@ -13,7 +15,89 @@ export default defineComponent({
13
15
  </script>
14
16
  <style lang="scss">
15
17
  .octopus-app .octopus-spinner {
18
+
19
+ --size-spinner: 3rem;
20
+ --size-spinner-section: calc(var(--size-spinner) / 20);
21
+ --half-size-spinner: calc(var(--size-spinner) / 2);
22
+
23
+ color: #000000;
16
24
  display: inline-block;
25
+ position: relative;
26
+ width: var(--size-spinner);
27
+ height: var(--size-spinner);
28
+
29
+ div {
30
+ transform-origin: var(--half-size-spinner) var(--half-size-spinner);
31
+ animation: octopus-spinner 1.2s linear infinite;
32
+ }
33
+ div:after {
34
+ content: " ";
35
+ display: block;
36
+ position: absolute;
37
+ top: 3px;
38
+ left: calc(var(--half-size-spinner) - calc(var(--size-spinner-section) / 2));
39
+ width: var(--size-spinner-section);
40
+ height: calc(var(--half-size-spinner) / 3);
41
+ border-radius: 20%;
42
+ background: currentColor;
43
+ }
44
+ div:nth-child(1) {
45
+ transform: rotate(0deg);
46
+ animation-delay: -1.1s;
47
+ }
48
+ div:nth-child(2) {
49
+ transform: rotate(30deg);
50
+ animation-delay: -1s;
51
+ }
52
+ div:nth-child(3) {
53
+ transform: rotate(60deg);
54
+ animation-delay: -0.9s;
55
+ }
56
+ div:nth-child(4) {
57
+ transform: rotate(90deg);
58
+ animation-delay: -0.8s;
59
+ }
60
+ div:nth-child(5) {
61
+ transform: rotate(120deg);
62
+ animation-delay: -0.7s;
63
+ }
64
+ div:nth-child(6) {
65
+ transform: rotate(150deg);
66
+ animation-delay: -0.6s;
67
+ }
68
+ div:nth-child(7) {
69
+ transform: rotate(180deg);
70
+ animation-delay: -0.5s;
71
+ }
72
+ div:nth-child(8) {
73
+ transform: rotate(210deg);
74
+ animation-delay: -0.4s;
75
+ }
76
+ div:nth-child(9) {
77
+ transform: rotate(240deg);
78
+ animation-delay: -0.3s;
79
+ }
80
+ div:nth-child(10) {
81
+ transform: rotate(270deg);
82
+ animation-delay: -0.2s;
83
+ }
84
+ div:nth-child(11) {
85
+ transform: rotate(300deg);
86
+ animation-delay: -0.1s;
87
+ }
88
+ div:nth-child(12) {
89
+ transform: rotate(330deg);
90
+ animation-delay: 0s;
91
+ }
92
+ @keyframes octopus-spinner {
93
+ 0% {
94
+ opacity: 1;
95
+ }
96
+ 100% {
97
+ opacity: 0;
98
+ }
99
+ }
100
+ /* display: inline-block;
17
101
  width: 2rem;
18
102
  height: 2rem;
19
103
  border-radius: 50%;
@@ -31,6 +115,6 @@ export default defineComponent({
31
115
  to {
32
116
  transform: rotate(360deg);
33
117
  }
34
- }
118
+ } */
35
119
  }
36
120
  </style>
@@ -7,7 +7,6 @@
7
7
  <div
8
8
  v-if="secondaryProgress"
9
9
  class="octopus-progress-bar bg-warning"
10
- role="progressbar"
11
10
  aria-valuenow="0"
12
11
  aria-valuemin="0"
13
12
  aria-valuemax="100"
@@ -28,7 +27,6 @@
28
27
  </template>
29
28
  <div
30
29
  class="octopus-progress-bar bg-primary"
31
- role="progressbar"
32
30
  aria-valuenow="0"
33
31
  aria-valuemin="0"
34
32
  aria-valuemax="100"
@@ -147,9 +145,75 @@ export default defineComponent({
147
145
  </script>
148
146
 
149
147
  <style lang="scss">
150
- @use "../../style/progressbar";
148
+ .octopus-app{
149
+ .octopus-progress{
150
+ display: flex;
151
+ overflow: hidden;
152
+ background-color:var(--octopus-secondary-lighter);
153
+ border-radius: var(--octopus-border-radius);
154
+ position: relative;
155
+ cursor: pointer;
156
+ .octopus-progress-bar{
157
+ position: absolute;
158
+ display: flex;
159
+ flex-direction: column;
160
+ justify-content: center;
161
+ overflow: hidden;
162
+ color: var(--octopus-color-on-primary);
163
+ text-align: center;
164
+ white-space: nowrap;
165
+ background-color: var(--octopus-primary);
166
+ transition: width 0.6s ease;
167
+ }
168
+
169
+ .octopus-chapter{
170
+ position: absolute;
171
+ background: transparent;
172
+ background-clip: content-box;
173
+ padding: 0 5px;
174
+ box-shadow: inset -2px 1px 0 0 black,
175
+ inset 2px 1px 0 0 black;
176
+
177
+ &:hover{
178
+ background: var(--octopus-background-transparent);
179
+ box-shadow: -4px 1px 0 0 black;
180
+ }
181
+ }
182
+
183
+ &,.octopus-progress-bar{
184
+ height: 4px;
185
+ @media (width <= 960px) {
186
+ height: 8px;
187
+ }
188
+ }
189
+
190
+ &.large,&.large .octopus-progress-bar{
191
+ height: 15px;
192
+ }
151
193
 
152
- .octopus-app .player-container {
194
+ &.medium,&.medium .octopus-progress-bar{
195
+ height: 6px;
196
+ }
197
+
198
+ .octopus-progress-bar-duration {
199
+ width: 10px;
200
+ }
201
+
202
+ .octopus-progress-bar-cursor{
203
+ width: 10px;
204
+ height: 10px;
205
+ border-radius: 50%;
206
+ background: black;
207
+ align-self: center;
208
+ position: absolute;
209
+ }
210
+
211
+ .end-0{
212
+ right: 0;
213
+ }
214
+ }
215
+
216
+ .player-container {
153
217
  .octopus-small-popover {
154
218
  font-size: 0.7rem;
155
219
  background: var(--octopus-player-color);
@@ -161,4 +225,5 @@ export default defineComponent({
161
225
  }
162
226
  }
163
227
  }
228
+ }
164
229
  </style>
@@ -308,12 +308,15 @@ export default defineComponent({
308
308
  color: white;
309
309
  font-weight: bold;
310
310
  font-size: 0.93rem;
311
+ text-decoration: underline;
312
+ text-decoration-color: transparent;
313
+ transition: text-decoration-color 250ms;
314
+ text-underline-offset: 8px;
311
315
 
312
316
  &.link-hover:hover,
313
317
  &.link-hover.router-link-exact-active.router-link-active {
314
318
  color: white;
315
- text-decoration: underline;
316
- text-underline-offset: 8px;
319
+ text-decoration-color: white;
317
320
  }
318
321
  }
319
322
 
@@ -1,15 +1,11 @@
1
1
  <template>
2
- <div class="octopus-progress ambiance-progress c-hand-auto mt-1">
3
- <div
4
- class="octopus-progress-bar"
5
- role="progressbar"
6
- aria-valuenow="0"
7
- aria-valuemin="0"
8
- aria-valuemax="100"
9
- :aria-label="$t('Advertising')"
10
- :style="'width: ' + adPercentProgress + '%'"
11
- />
12
- </div>
2
+ <progress
3
+ class="ambiance-progress c-hand-auto mt-1"
4
+ min="0"
5
+ max="100"
6
+ :value="adPercentProgress"
7
+ :aria-label="$t('Advertising')"
8
+ />
13
9
  </template>
14
10
 
15
11
  <script lang="ts">
@@ -22,7 +18,4 @@ export default defineComponent({
22
18
  ...mapState(useVastStore, ["adPercentProgress"]),
23
19
  },
24
20
  });
25
- </script>
26
- <style lang="scss">
27
- @use "../../../../style/progressbar";
28
- </style>
21
+ </script>
@@ -1,18 +1,12 @@
1
1
  <template>
2
- <div
3
- class="octopus-progress c-hand-auto mt-1"
2
+ <progress
3
+ class="c-hand-auto mt-1"
4
+ min="0"
5
+ max="100"
6
+ :value="percentProgress"
7
+ :aria-label="$t('Radio')"
4
8
  :class="isAmbiance ? 'ambiance-progress' : ''"
5
- >
6
- <div
7
- class="octopus-progress-bar"
8
- role="progressbar"
9
- aria-valuenow="0"
10
- aria-valuemin="0"
11
- aria-valuemax="100"
12
- :aria-label="$t('Radio')"
13
- :style="'width: ' + percentProgress + '%'"
14
- />
15
- </div>
9
+ />
16
10
  </template>
17
11
 
18
12
  <script lang="ts">
@@ -51,12 +45,7 @@ export default defineComponent({
51
45
  },
52
46
  methods: {
53
47
  ...mapActions(usePlayerStore, ["playerUpdateElapsed"]),
54
- handlePercentInterval(/* clear: boolean */): void {
55
- /* if(clear){
56
- clearInterval((this.percentInterval as unknown as number));
57
- this.percentInterval = undefined;
58
- return;
59
- } */
48
+ handlePercentInterval(): void {
60
49
  this.percentInterval = setInterval(() => {
61
50
  this.calculatePercent();
62
51
  }, 1000);
@@ -79,6 +68,3 @@ export default defineComponent({
79
68
  },
80
69
  });
81
70
  </script>
82
- <style lang="scss">
83
- @use "../../../../style/progressbar";
84
- </style>
@@ -5,13 +5,15 @@
5
5
  <WindowCloseIcon />
6
6
  </button>
7
7
  <div class="video-wrapper">
8
- <PlayerVideoDigiteka v-if="!playerLive" :video-id="videoId" />
8
+ <PlayerYoutubeEmbed v-if="youtubeId" :youtube-id="youtubeId" />
9
+ <PlayerVideoDigiteka v-else-if="!playerLive" :video-id="playerPodcast?.video?.videoId" />
9
10
  <PlayerVideoHls v-else :hls-url="hlsVideoUrl" />
10
11
  </div>
11
12
  </template>
12
13
  </teleport>
13
14
  </template>
14
15
  <script lang="ts">
16
+ import youtubeVideoHelper from "../../../../helper/youtubeVideoHelper";
15
17
  import WindowCloseIcon from "vue-material-design-icons/WindowClose.vue";
16
18
  import { usePlayerStore } from "../../../../stores/PlayerStore";
17
19
  import { useApiStore } from "../../../../stores/ApiStore";
@@ -23,16 +25,22 @@ const PlayerVideoDigiteka = defineAsyncComponent(
23
25
  const PlayerVideoHls = defineAsyncComponent(
24
26
  () => import("../video/PlayerVideoHls.vue"),
25
27
  );
28
+ const PlayerYoutubeEmbed = defineAsyncComponent(
29
+ () => import("../video/PlayerYoutubeEmbed.vue"),
30
+ );
26
31
  export default defineComponent({
27
32
  name: "PlayerVideo",
28
33
 
29
34
  components: {
30
35
  PlayerVideoDigiteka,
31
36
  PlayerVideoHls,
37
+ PlayerYoutubeEmbed,
32
38
  WindowCloseIcon,
33
39
  },
34
40
  data() {
35
- return {};
41
+ return {
42
+ youtubeId: undefined as string|undefined,
43
+ };
36
44
  },
37
45
  computed: {
38
46
  ...mapState(useApiStore, ["hlsUrl"]),
@@ -43,9 +51,9 @@ export default defineComponent({
43
51
  }
44
52
  return `${this.hlsUrl}live/video_dev.${this.playerLive.conferenceId}/index.m3u8`;
45
53
  },
46
- videoId(): string | undefined {
47
- return this.playerPodcast?.video?.videoId;
48
- },
54
+ },
55
+ created(){
56
+ this.youtubeId = youtubeVideoHelper.getYoutubeId((this.playerPodcast ?? this.playerLive )?.tags ?? []);
49
57
  },
50
58
 
51
59
  methods: {
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <iframe
3
+ width="500"
4
+ height="281"
5
+ :title="$t('Video')"
6
+ class="youtube-iframe"
7
+ :src="'https://www.youtube.com/embed/'+youtubeId"
8
+ frameborder="0"
9
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
10
+ referrerpolicy="strict-origin-when-cross-origin"
11
+ allowfullscreen>
12
+ </iframe>
13
+ </template>
14
+
15
+ <script lang="ts">
16
+ import { defineComponent } from "vue";
17
+ export default defineComponent({
18
+ name: "PlayerYoutubeEmbed",
19
+ components: {
20
+ },
21
+ props: {
22
+ youtubeId: { default: undefined, type: String },
23
+ },
24
+
25
+ });
26
+ </script>
27
+ <style lang="scss">
28
+ @use "../../../../style/videoPlayer";
29
+ </style>
@@ -21,7 +21,7 @@
21
21
  :organisation-id="podcast.organisation.id"
22
22
  />
23
23
  <SharePlayer
24
- v-if="!isPodcastmaker && editRight"
24
+ v-if="!isPodcastmaker && editRight && !youtubeId"
25
25
  :podcast="podcast"
26
26
  :emission="podcast?.emission"
27
27
  :organisation-id="authOrgaId"
@@ -68,6 +68,7 @@
68
68
  </template>
69
69
 
70
70
  <script lang="ts">
71
+ import youtubeVideoHelper from "../../helper/youtubeVideoHelper";
71
72
  import {useOrgaComputed} from "../composable/useOrgaComputed";
72
73
  import PodcastInlineList from "../display/podcasts/PodcastInlineList.vue";
73
74
  import PodcastModuleBox from "../display/podcasts/PodcastModuleBox.vue";
@@ -135,6 +136,7 @@ export default defineComponent({
135
136
  error: false as boolean,
136
137
  fetchConference: undefined as Conference | undefined,
137
138
  infoReload: undefined as ReturnType<typeof setTimeout> | undefined,
139
+ youtubeId: undefined as string|undefined,
138
140
  };
139
141
  },
140
142
 
@@ -312,6 +314,9 @@ export default defineComponent({
312
314
  this.podcastInProcessing();
313
315
  this.updatePathParams(this.podcast.title);
314
316
  await this.getCommentsConfig(this.podcast);
317
+ if((this.fetchConference?.videoProfile?.includes("video_") && "READY_TO_RECORD" === this.podcast.processingStatus) || undefined !== this.podcast.video?.videoId){
318
+ this.youtubeId = youtubeVideoHelper.getYoutubeId(this.podcast?.tags ?? []);
319
+ }
315
320
  this.loaded = true;
316
321
  } catch (error) {
317
322
  this.handle403(error as AxiosError);
@@ -0,0 +1,13 @@
1
+ export default {
2
+ getYoutubeId(tags: Array<string>){
3
+ let youtubeId = undefined;
4
+ for(const tag of tags){
5
+ const regexExec = /^\[\[https:\/\/(?:www.)?youtube.com\/(?:watch\?v=|live\/)(?<id>\S+)\]\]$/.exec(tag);
6
+ if(regexExec?.groups?.id){
7
+ youtubeId = regexExec.groups.id;
8
+ break;
9
+ }
10
+ }
11
+ return youtubeId;
12
+ }
13
+ }
@@ -4,7 +4,6 @@ import relativeTime from "dayjs/plugin/relativeTime";
4
4
  dayjs.extend(relativeTime);
5
5
 
6
6
  import { defineStore } from "pinia";
7
- import StringHelper from "../helper/stringHelper";
8
7
  import cookiesHelper from "../helper/cookiesHelper";
9
8
  import WebSocketEngine from "../websocket/commentWebsocket";
10
9
  import { CommentPodcast } from "./class/general/comment";
@@ -224,7 +223,7 @@ export const useCommentStore = defineStore("CommentStore", {
224
223
  async initialize() {
225
224
  const apiStore = useApiStore();
226
225
  const commentUrl = apiStore.commentUrl?? "https://comments.dev2.saooti.org/";
227
- const url = StringHelper.trimChar(commentUrl.replace("https://", ""),"/");
226
+ const url = stringHelper.trimChar(commentUrl.replace("https://", ""),"/");
228
227
  const engine = new WebSocketEngine(url);
229
228
  await engine.initialize();
230
229
  this.commentWebsocketengine = engine;
@@ -4,11 +4,6 @@ html{
4
4
  font-size: 20px;
5
5
  height: 100%;
6
6
  scrollbar-gutter: stable;
7
- /* scroll-snap-type: y proximity;
8
- scroll-padding-top: 5rem;
9
- @media (width <= 650px) {
10
- scroll-padding-top: 3.5rem;
11
- } */
12
7
  }
13
8
 
14
9
  body{
@@ -30,14 +25,6 @@ main, #app{
30
25
  flex-grow: 1;
31
26
  }
32
27
 
33
- /* header, section:not(.page-box), .podcast-inline-container {
34
- scroll-snap-align: start;
35
- }
36
- .page-element > section:first-child {
37
- scroll-snap-align: none;
38
- }
39
- */
40
-
41
28
 
42
29
  /** Octopus style */
43
30
 
@@ -47,8 +47,8 @@
47
47
  }
48
48
 
49
49
  .img-box-podcast{
50
- height: calc(var(--octopus-podcast-size) - 4px);
51
- width: calc(var(--octopus-podcast-size) - 4px);
50
+ height: calc(var(--octopus-podcast-size) - 2px);
51
+ width: calc(var(--octopus-podcast-size) - 2px);
52
52
  }
53
53
 
54
54
  .img-box,.img-box.img-box-podcast{
@@ -197,5 +197,39 @@
197
197
  text-align: center;
198
198
  }
199
199
 
200
+ progress{
201
+ display: flex;
202
+ flex-direction: column;
203
+ justify-content: center;
204
+ overflow: hidden;
205
+ color: var(--octopus-color-on-primary);
206
+ text-align: center;
207
+ white-space: nowrap;
208
+ background-color:var(--octopus-secondary-lighter);
209
+ border-radius: var(--octopus-border-radius);
210
+ cursor: pointer;
211
+ height: 4px;
212
+ flex-grow: 1;
213
+ width:100%;
214
+ @media (width <= 960px) {
215
+ height: 8px;
216
+ }
217
+ &::-webkit-progress-bar{
218
+ background-color: var(--octopus-secondary-lighter);
219
+ }
220
+ &:not(.ambiance-progress)::-webkit-progress-value {
221
+ background-color: var(--octopus-primary);
222
+ }
223
+ &.ambiance-progress::-webkit-progress-value {
224
+ background-color: var(--octopus-text-disabled);
225
+ }
226
+ &.large{
227
+ height: 15px;
228
+ }
229
+
230
+ &.medium{
231
+ height: 6px;
232
+ }
233
+ }
200
234
 
201
235
  }
@@ -1,77 +0,0 @@
1
- .octopus-app{
2
- .octopus-progress{
3
- display: flex;
4
- overflow: hidden;
5
- background-color:var(--octopus-secondary-lighter);
6
- border-radius: var(--octopus-border-radius);
7
- position: relative;
8
- cursor: pointer;
9
-
10
- .octopus-progress-bar{
11
- position: absolute;
12
- display: flex;
13
- flex-direction: column;
14
- justify-content: center;
15
- overflow: hidden;
16
- color: var(--octopus-color-on-primary);
17
- text-align: center;
18
- white-space: nowrap;
19
- background-color: var(--octopus-primary);
20
- transition: width 0.6s ease;
21
- }
22
-
23
- .octopus-chapter{
24
- position: absolute;
25
- background: transparent;
26
- background-clip: content-box;
27
- padding: 0 5px;
28
- box-shadow: inset -2px 1px 0 0 black,
29
- inset 2px 1px 0 0 black;
30
-
31
- &:hover{
32
- background: var(--octopus-background-transparent);
33
- box-shadow: -4px 1px 0 0 black;
34
- }
35
- }
36
-
37
- &,.octopus-progress-bar{
38
- height: 4px;
39
-
40
- @media (width <= 960px) {
41
- height: 8px;
42
- }
43
- }
44
-
45
- &.large,&.large .octopus-progress-bar{
46
- height: 15px;
47
- }
48
-
49
- &.medium,&.medium .octopus-progress-bar{
50
- height: 6px;
51
- }
52
-
53
- .octopus-progress-bar-duration {
54
- width: 10px;
55
- }
56
-
57
- .octopus-progress-bar-cursor{
58
- width: 10px;
59
- height: 10px;
60
- border-radius: 50%;
61
- background: black;
62
- align-self: center;
63
- position: absolute;
64
- }
65
-
66
- .end-0{
67
- right: 0;
68
- }
69
- }
70
-
71
- .octopus-progress.ambiance-progress {
72
- .octopus-progress-bar {
73
- background-color: var(--octopus-text-disabled);
74
- }
75
- }
76
-
77
- }