@saooti/octopus-sdk 37.0.17 → 37.0.19

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 (25) hide show
  1. package/package.json +25 -22
  2. package/src/components/display/emission/EmissionInlineList.vue +4 -4
  3. package/src/components/display/filter/AdvancedSearch.vue +10 -0
  4. package/src/components/display/list/ListPaginate.vue +1 -1
  5. package/src/components/display/list/SwiperList.vue +13 -9
  6. package/src/components/display/live/LiveItem.vue +10 -1
  7. package/src/components/display/playlist/PodcastPlaylistInlineList.vue +3 -3
  8. package/src/components/display/podcasts/PodcastImage.vue +17 -12
  9. package/src/components/display/podcasts/PodcastInlineListClassic.vue +3 -3
  10. package/src/components/display/sharing/ShareDistribution.vue +1 -1
  11. package/src/components/display/sharing/SubscribeButtons.vue +6 -1
  12. package/src/components/form/ClassicDatePicker.vue +46 -33
  13. package/src/components/misc/ClassicPopover.vue +6 -4
  14. package/src/components/misc/player/PlayerCompact.vue +1 -1
  15. package/src/components/misc/player/PlayerComponent.vue +8 -10
  16. package/src/components/misc/player/PlayerLarge.vue +1 -1
  17. package/src/components/misc/player/PlayerVideo.vue +25 -30
  18. package/src/components/misc/player/PlayerVideoDigiteka.vue +28 -26
  19. package/src/components/misc/player/PlayerVideoHls.vue +108 -90
  20. package/src/components/misc/player/radio/RadioHistory.vue +12 -9
  21. package/src/components/misc/player/radio/RadioProgressBar.vue +2 -2
  22. package/src/components/pages/EmissionPage.vue +1 -1
  23. package/src/components/pages/PodcastPage.vue +1 -1
  24. package/src/components/pages/PodcastsPage.vue +3 -0
  25. package/src/locale/fr.ts +4 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "37.0.17",
3
+ "version": "37.0.19",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -14,49 +14,52 @@
14
14
  "test": "jest --coverage"
15
15
  },
16
16
  "dependencies": {
17
- "@clappr/core": "0.4.27",
18
- "@clappr/hlsjs-playback": "^1.1.0",
19
17
  "@popperjs/core": "^2.11.8",
20
- "@saooti/octopus-api": "^0.34.3",
21
- "@tiptap/extension-link": "^2.0.4",
22
- "@tiptap/extension-underline": "^2.0.4",
23
- "@tiptap/pm": "^2.0.4",
24
- "@tiptap/starter-kit": "^2.0.4",
25
- "@tiptap/vue-3": "^2.0.4",
18
+ "@saooti/octopus-api": "^0.36.0",
19
+ "@tiptap/extension-link": "^2.1.6",
20
+ "@tiptap/extension-underline": "^2.1.6",
21
+ "@tiptap/pm": "^2.1.6",
22
+ "@tiptap/starter-kit": "^2.1.6",
23
+ "@tiptap/vue-3": "^2.1.6",
26
24
  "@vue/cli": "^5.0.8",
27
25
  "@vue/compat": "^3.3.4",
28
- "@vuepic/vue-datepicker": "^5.4.0",
29
- "autoprefixer": "^10.4.14",
26
+ "@vuepic/vue-datepicker": "^6.0.1",
27
+ "autoprefixer": "^10.4.15",
30
28
  "axios": "^1.4.0",
31
29
  "dayjs": "^1.11.9",
32
- "eslint-config-prettier": "^8.8.0",
30
+ "eslint-config-prettier": "^9.0.0",
33
31
  "eslint-plugin-prettier": "^5.0.0",
34
32
  "express": "^4.18.2",
35
- "hls.js": "^1.4.9",
33
+ "hls.js": "^1.4.10",
36
34
  "humanize-duration": "^3.29.0",
37
- "jest": "^29.6.1",
38
- "pinia": "^2.1.4",
39
- "qrcode.vue": "^3.4.0",
40
- "sass": "^1.63.6",
35
+ "jest": "^29.6.2",
36
+ "pinia": "^2.1.6",
37
+ "qrcode.vue": "^3.4.1",
38
+ "sass": "^1.66.1",
41
39
  "sonarqube-scanner": "^3.0.0",
42
- "swiper": "^10.0.4",
43
- "vite": "^4.4.4",
40
+ "swiper": "^10.2.0",
41
+ "video.js": "^7.21.5",
42
+ "videojs-contrib-quality-levels": "^2.2.1",
43
+ "videojs-hls-quality-selector": "^1.1.4",
44
+ "vite": "^4.4.9",
44
45
  "vue": "^3.3.4",
45
46
  "vue-i18n": "^9.2.2",
46
47
  "vue-recaptcha": "^2.0.3",
47
48
  "vue-router": "^4.2.4",
48
49
  "vue-select": "^4.0.0-beta.6",
49
- "vue3-lazyload": "^0.3.6",
50
+ "vue3-lazyload": "^0.3.8",
50
51
  "vue3-swatches": "^1.2.3"
51
52
  },
52
53
  "devDependencies": {
54
+ "@types/videojs-contrib-quality-levels": "^2.0.1",
55
+ "@types/videojs-hls-quality-selector": "^1.1.0",
53
56
  "@types/vue-select": "^3.16.2",
54
57
  "@typescript-eslint/eslint-plugin": "^6.0.0",
55
58
  "@typescript-eslint/parser": "^6.0.0",
56
- "@vitejs/plugin-vue": "^4.2.3",
59
+ "@vitejs/plugin-vue": "^4.3.2",
57
60
  "@vue/compiler-sfc": "^3.3.4",
58
61
  "@vue/eslint-config-typescript": "^11.0.3",
59
- "eslint": "^8.45.0",
62
+ "eslint": "^8.47.0",
60
63
  "eslint-plugin-vue": "^9.15.1",
61
64
  "typescript": "^5.1.6"
62
65
  },
@@ -64,7 +64,7 @@ import { Rubrique } from "@/stores/class/rubrique/rubrique";
64
64
  import { defineComponent } from "vue";
65
65
  import { AxiosError } from "axios";
66
66
  import imageProxy from "../../mixins/imageProxy";
67
- import resizePhone from "../../mixins/resizePhone";
67
+ import resizePhone from "../../mixins/resizePhone";
68
68
  import { Rubriquage } from "@/stores/class/rubrique/rubriquage";
69
69
  export default defineComponent({
70
70
  name: "EmissionInlineList",
@@ -100,7 +100,7 @@ export default defineComponent({
100
100
  alignLeft: false as boolean,
101
101
  rubriques: undefined as Array<Rubrique> | undefined,
102
102
  isPhone: false as boolean,
103
- windowWidth: 0 as number
103
+ windowWidth: 0 as number,
104
104
  };
105
105
  },
106
106
 
@@ -132,7 +132,7 @@ export default defineComponent({
132
132
  sizeItem() {
133
133
  this.handleResize();
134
134
  },
135
- windowWidth(){
135
+ windowWidth() {
136
136
  if (!this.$el) return;
137
137
  if (this.overflowScroll) {
138
138
  this.size = 20;
@@ -145,7 +145,7 @@ export default defineComponent({
145
145
  const width = (this.$el as HTMLElement).offsetWidth;
146
146
  const sixteen = domHelper.convertRemToPixels(this.itemSize + 0.7);
147
147
  this.size = Math.floor(width / sixteen);
148
- }
148
+ },
149
149
  },
150
150
 
151
151
  mounted() {
@@ -51,6 +51,14 @@
51
51
  :label="textNotValidate"
52
52
  />
53
53
  </div>
54
+ <ClassicCheckbox
55
+ v-if="!isEmission"
56
+ :text-init="onlyVideo"
57
+ class="flex-shrink-0 mt-3"
58
+ id-checkbox="only-video-checkbox"
59
+ :label="$t('Show only episodes with video')"
60
+ @update:text-init="$emit('update:onlyVideo', $event)"
61
+ />
54
62
  </div>
55
63
  <div class="d-flex flex-column">
56
64
  <div class="text-primary mb-2">
@@ -96,6 +104,7 @@ export default defineComponent({
96
104
  isEducation: { default: false, type: Boolean },
97
105
  includeHidden: { default: false, type: Boolean },
98
106
  sortCriteria: { default: "DATE", type: String },
107
+ onlyVideo: { default: false, type: Boolean },
99
108
  },
100
109
 
101
110
  emits: [
@@ -107,6 +116,7 @@ export default defineComponent({
107
116
  "includeHidden",
108
117
  "notValid",
109
118
  "updateRubriquageFilter",
119
+ "update:onlyVideo",
110
120
  ],
111
121
  data() {
112
122
  return {
@@ -82,7 +82,7 @@ export default defineComponent({
82
82
  data() {
83
83
  return {
84
84
  isPhone: false as boolean,
85
- windowWidth: 0 as number
85
+ windowWidth: 0 as number,
86
86
  };
87
87
  },
88
88
  computed: {
@@ -1,7 +1,11 @@
1
1
  <template>
2
2
  <div class="position-relative w-100">
3
3
  <template v-if="!isPhone">
4
- <button class="btn-transparent swiper-button-prev" v-show="isLoop" @click="slidePrevButton()"></button>
4
+ <button
5
+ v-show="isLoop"
6
+ class="btn-transparent swiper-button-prev"
7
+ @click="slidePrevButton()"
8
+ ></button>
5
9
  <swiper
6
10
  :slides-per-view="numberItem"
7
11
  :space-between="0"
@@ -14,7 +18,7 @@
14
18
  </swiper-slide>
15
19
  </swiper>
16
20
  </template>
17
- <div class="element-list-inline" v-else>
21
+ <div v-else class="element-list-inline">
18
22
  <div v-for="(obj, index) in listObject" :key="obj">
19
23
  <slot name="octopusSlide" :option="obj" :index="index" />
20
24
  </div>
@@ -38,7 +42,7 @@ export default defineComponent({
38
42
  Swiper,
39
43
  SwiperSlide,
40
44
  },
41
- mixins:[resizePhone],
45
+ mixins: [resizePhone],
42
46
 
43
47
  props: {
44
48
  listObject: { default: () => [], type: Array as () => Array<unknown> },
@@ -50,7 +54,7 @@ export default defineComponent({
50
54
  modules: [Navigation],
51
55
  numberItem: 5 as number,
52
56
  isPhone: false as boolean,
53
- windowWidth: 0 as number
57
+ windowWidth: 0 as number,
54
58
  };
55
59
  },
56
60
  computed: {
@@ -65,21 +69,21 @@ export default defineComponent({
65
69
  ? state.generalParameters.podcastItem
66
70
  : 13.5;
67
71
  },
68
- isLoop():boolean{
72
+ isLoop(): boolean {
69
73
  return this.listObject.length >= this.numberItem;
70
74
  },
71
75
  },
72
- watch:{
73
- windowWidth(){
76
+ watch: {
77
+ windowWidth() {
74
78
  if (!this.$el) return;
75
79
  const width = (this.$el as HTMLElement).offsetWidth - 95;
76
80
  const sixteen = domHelper.convertRemToPixels(this.sizeItem + 0.5);
77
81
  this.numberItem = Math.max(1, Math.floor(width / sixteen));
78
- }
82
+ },
79
83
  },
80
84
 
81
85
  methods: {
82
- slidePrevButton(){
86
+ slidePrevButton() {
83
87
  this.$el.querySelector(".swiper").swiper.slidePrev();
84
88
  },
85
89
  },
@@ -29,6 +29,7 @@ export default defineComponent({
29
29
  data() {
30
30
  return {
31
31
  live: undefined as Podcast | undefined,
32
+ watchInterval: undefined as ReturnType<typeof setTimeout> | undefined,
32
33
  };
33
34
  },
34
35
 
@@ -36,7 +37,14 @@ export default defineComponent({
36
37
  this.fetchPodcastData();
37
38
  this.watchStatus();
38
39
  },
40
+ unmounted() {
41
+ this.clearWatchStatus();
42
+ },
39
43
  methods: {
44
+ clearWatchStatus() {
45
+ clearInterval(this.watchInterval as unknown as number);
46
+ this.watchInterval = undefined;
47
+ },
40
48
  async fetchPodcastData(): Promise<void> {
41
49
  if (!this.fetchConference || !this.fetchConference.podcastId) return;
42
50
  try {
@@ -73,7 +81,8 @@ export default defineComponent({
73
81
  ...{ status: newStatus },
74
82
  });
75
83
  } else {
76
- setTimeout(() => {
84
+ this.clearWatchStatus();
85
+ this.watchInterval = setTimeout(() => {
77
86
  this.watchStatus();
78
87
  }, 5000);
79
88
  }
@@ -88,7 +88,7 @@ export default defineComponent({
88
88
  direction: 1 as number,
89
89
  alignLeft: false as boolean,
90
90
  isPhone: false as boolean,
91
- windowWidth: 0 as number
91
+ windowWidth: 0 as number,
92
92
  };
93
93
  },
94
94
  computed: {
@@ -124,7 +124,7 @@ export default defineComponent({
124
124
  this.reset();
125
125
  this.fetchContent();
126
126
  },
127
- windowWidth(){
127
+ windowWidth() {
128
128
  if (!this.$el) return;
129
129
  if (this.overflowScroll) {
130
130
  this.size = 20;
@@ -137,7 +137,7 @@ export default defineComponent({
137
137
  const width = (this.$el as HTMLElement).offsetWidth;
138
138
  const sixteen = domHelper.convertRemToPixels(this.sizeItem + 0.8);
139
139
  this.size = Math.floor(width / sixteen);
140
- }
140
+ },
141
141
  },
142
142
 
143
143
  mounted() {
@@ -61,7 +61,7 @@
61
61
  {{ textVisible }}
62
62
  </div>
63
63
  </button>
64
- <button
64
+ <button
65
65
  v-if="isVideoPodcast"
66
66
  class="btn admin-button btn-play-video saooti-video"
67
67
  @click="play(true)"
@@ -107,10 +107,13 @@ export default defineComponent({
107
107
  "playerPodcast",
108
108
  "playerLive",
109
109
  "playerStatus",
110
- "playerVideo"
110
+ "playerVideo",
111
111
  ]),
112
- isVideoPodcast(): boolean{
113
- return this.fetchConference?.videoProfile?.includes('video_') || undefined!==this.podcast.video?.videoId;
112
+ isVideoPodcast(): boolean {
113
+ return (
114
+ this.fetchConference?.videoProfile?.includes("video_") ||
115
+ undefined !== this.podcast.video?.videoId
116
+ );
114
117
  },
115
118
  playingPodcast() {
116
119
  return (
@@ -214,7 +217,6 @@ export default defineComponent({
214
217
  case "RECORDING":
215
218
  return this.$t("In live");
216
219
  case "DEBRIEFING":
217
- /* if (!this.isAnimatorLive) return ''; */
218
220
  if ("READY_TO_RECORD" === this.podcast.processingStatus)
219
221
  return this.$t("Not recording");
220
222
  return this.$t("Debriefing");
@@ -261,17 +263,20 @@ export default defineComponent({
261
263
  if (this.isLiveToBeRecorded) {
262
264
  return;
263
265
  }
264
- if (this.playingPodcast && isVideo===this.playerVideo) {
266
+ if (this.playingPodcast && isVideo === this.playerVideo) {
265
267
  this.playerChangeStatus("PLAYING" === this.playerStatus);
266
268
  return;
267
269
  }
268
270
  if (!this.recordingLive) {
269
271
  this.playerPlay(this.podcast, isVideo);
270
272
  } else {
271
- this.playerPlay({
272
- ...this.podcast,
273
- ...{ conferenceId: this.fetchConference?.conferenceId },
274
- }, isVideo);
273
+ this.playerPlay(
274
+ {
275
+ ...this.podcast,
276
+ ...{ conferenceId: this.fetchConference?.conferenceId },
277
+ },
278
+ isVideo,
279
+ );
275
280
  }
276
281
  if (this.clickPlayGoPage) {
277
282
  this.$router.push("/main/pub/podcast/" + this.podcast.podcastId);
@@ -319,13 +324,13 @@ export default defineComponent({
319
324
  background-color: rgba(255, 255, 255, 0.5);
320
325
  }
321
326
 
322
- .btn.btn-play-video{
327
+ .btn.btn-play-video {
323
328
  position: absolute;
324
329
  bottom: 0;
325
330
  right: 0;
326
331
  margin: 0.5rem;
327
332
  background: $primaryColorLessTransparent !important;
328
- color:white !important
333
+ color: white !important;
329
334
  }
330
335
 
331
336
  .image-play-button .play-button-error-icon {
@@ -99,7 +99,7 @@ export default defineComponent({
99
99
  direction: 1 as number,
100
100
  alignLeft: false as boolean,
101
101
  isPhone: false as boolean,
102
- windowWidth: 0 as number
102
+ windowWidth: 0 as number,
103
103
  };
104
104
  },
105
105
  computed: {
@@ -142,7 +142,7 @@ export default defineComponent({
142
142
  this.reset();
143
143
  this.fetchNext();
144
144
  },
145
- windowWidth(){
145
+ windowWidth() {
146
146
  if (!this.$el) return;
147
147
  if (this.overflowScroll) {
148
148
  this.size = 20;
@@ -155,7 +155,7 @@ export default defineComponent({
155
155
  const width = (this.$el as HTMLElement).offsetWidth;
156
156
  const sixteen = domHelper.convertRemToPixels(this.sizeItem + 0.8);
157
157
  this.size = Math.floor(width / sixteen);
158
- }
158
+ },
159
159
  },
160
160
 
161
161
  created() {
@@ -77,7 +77,7 @@ export default defineComponent({
77
77
  icon: "saooti-google-podcasts",
78
78
  title: "Google Podcasts",
79
79
  },
80
- {url:this.getUrl('iHeart'), icon:'saooti-iheart', title:'iHeart'},
80
+ { url: this.getUrl("iHeart"), icon: "saooti-iheart", title: "iHeart" },
81
81
  {
82
82
  url: this.getUrl("PlayerFM"),
83
83
  icon: "saooti-playerfm",
@@ -56,7 +56,12 @@ export default defineComponent({
56
56
  title: "Google Podcasts",
57
57
  url: this.getUrl("googlePodcasts"),
58
58
  },
59
- {name:'iHeart', icon:"saooti-iheart",title:'iHeart', url : this.getUrl('iHeart')},
59
+ {
60
+ name: "iHeart",
61
+ icon: "saooti-iheart",
62
+ title: "iHeart",
63
+ url: this.getUrl("iHeart"),
64
+ },
60
65
  {
61
66
  name: "playerFm",
62
67
  icon: "saooti-playerfm",
@@ -13,9 +13,9 @@
13
13
  :max-date="isMaxDate && !isTimePicker ? now : undefined"
14
14
  :min-date="isMinDate && !isTimePicker ? now : undefined"
15
15
  :range="undefined !== range"
16
- :multi-calendars="columnNumber>1 ? columnNumber : false"
16
+ :multi-calendars="columnNumber > 1 ? columnNumber : false"
17
17
  :inline="columnNumber > 1"
18
- :enable-time-picker="!isTimePicker ?displayTimePicker : undefined"
18
+ :enable-time-picker="!isTimePicker ? displayTimePicker : undefined"
19
19
  :aria-labels="ariaLabels"
20
20
  @update:model-value="$emit('updateDate', $event)"
21
21
  >
@@ -24,72 +24,85 @@
24
24
 
25
25
  <script lang="ts">
26
26
  import dayjs from "dayjs";
27
- import VueDatePicker from '@vuepic/vue-datepicker';
27
+ import VueDatePicker from "@vuepic/vue-datepicker";
28
28
  import { defineComponent } from "vue";
29
29
  export default defineComponent({
30
30
  components: {
31
31
  VueDatePicker,
32
32
  },
33
33
  props: {
34
- time: { default:undefined, type: Object as () => {hours:number, minutes:number, seconds:number} },
34
+ time: {
35
+ default: undefined,
36
+ type: Object as () => { hours: number; minutes: number; seconds: number },
37
+ },
35
38
  date: { default: undefined, type: Date },
36
- range: {default: undefined,type: Array as () => Array<Date>},
39
+ range: { default: undefined, type: Array as () => Array<Date> },
37
40
  isMaxDate: { default: false, type: Boolean },
38
41
  isMinDate: { default: false, type: Boolean },
39
42
  columnNumber: { default: 1, type: Number },
40
43
  displaySeconds: { default: false, type: Boolean },
41
- displayTimePicker:{ default: true, type: Boolean },
42
- isTimePicker:{ default: false, type: Boolean },
43
- useTeleport:{ default: false, type: Boolean },
44
+ displayTimePicker: { default: true, type: Boolean },
45
+ isTimePicker: { default: false, type: Boolean },
46
+ useTeleport: { default: false, type: Boolean },
44
47
  templateClass: { default: undefined, type: String },
45
48
  readonly: { default: false, type: Boolean },
46
49
  },
47
50
 
48
51
  emits: ["updateDate", "update:date"],
49
52
  data() {
50
- return {
51
- };
53
+ return {};
52
54
  },
53
55
  computed: {
54
- ariaLabels(){
56
+ ariaLabels() {
55
57
  return {
56
58
  input: this.date ? this.formatDate(this.date) : undefined,
57
- day : (value: {value: Date}) => {return this.formatDate(value.value);}
58
- }
59
+ day: (value: { value: Date }) => {
60
+ return this.formatDate(value.value);
61
+ },
62
+ };
59
63
  },
60
- modelVal(){
64
+ modelVal() {
61
65
  return this.time ?? this.range ?? this.date;
62
66
  },
63
- formatLocale(){
67
+ formatLocale() {
64
68
  return this.$i18n.locale;
65
69
  },
66
- format(){
67
- let timeString = '';
68
- if(this.displayTimePicker || this.isTimePicker){
69
- timeString ='HH:mm';
70
- if(this.displaySeconds){
71
- timeString ='HH:mm:ss';
72
- }
70
+ format() {
71
+ let timeString = "";
72
+ if (this.displayTimePicker || this.isTimePicker) {
73
+ timeString = "HH:mm";
74
+ if (this.displaySeconds) {
75
+ timeString = "HH:mm:ss";
76
+ }
73
77
  }
74
- const dayString = this.isTimePicker ? timeString : 'dd/MM/yyyy '+timeString;
75
- return this.range ? dayString+' - '+dayString : dayString;
78
+ const dayString = this.isTimePicker
79
+ ? timeString
80
+ : "dd/MM/yyyy " + timeString;
81
+ return this.range ? dayString + " - " + dayString : dayString;
76
82
  },
77
83
  now(): Date {
78
84
  return dayjs().toDate();
79
85
  },
80
86
  },
81
- methods:{
82
- formatDate(value: Date): string{
87
+ methods: {
88
+ formatDate(value: Date): string {
83
89
  const realMonth = value.getMonth() + 1;
84
- return value.getDate()+'/'+(realMonth < 10 ? "0" : "") + realMonth+'/'+value.getFullYear();
85
- }
86
- }
87
- })
90
+ return (
91
+ value.getDate() +
92
+ "/" +
93
+ (realMonth < 10 ? "0" : "") +
94
+ realMonth +
95
+ "/" +
96
+ value.getFullYear()
97
+ );
98
+ },
99
+ },
100
+ });
88
101
  </script>
89
102
  <style lang="scss">
90
- @import '@vuepic/vue-datepicker/dist/main.css';
103
+ @import "@vuepic/vue-datepicker/dist/main.css";
91
104
  .dp__theme_light {
92
- --dp-primary-color: #1a8658;
93
- --dp-time-font-size: 1rem;
105
+ --dp-primary-color: #1a8658;
106
+ --dp-time-font-size: 1rem;
94
107
  }
95
108
  </style>
@@ -32,7 +32,6 @@ export default defineComponent({
32
32
  relativeClass: { type: String, default: undefined },
33
33
  leftPos: { type: Boolean, default: false },
34
34
  topPos: { type: Boolean, default: false },
35
-
36
35
  },
37
36
  data() {
38
37
  return {
@@ -125,9 +124,12 @@ export default defineComponent({
125
124
  parentRight -
126
125
  (this.$refs.popover as HTMLElement).clientWidth
127
126
  : rectElement.left - parentLeft;
128
- const yPosParent = this.topPos ? rectElement.top:rectElement.bottom;
129
- const yGap = this.topPos ? -5 - (this.$refs.popover as HTMLElement).clientHeight :5;
130
- this.posY = yPosParent +
127
+ const yPosParent = this.topPos ? rectElement.top : rectElement.bottom;
128
+ const yGap = this.topPos
129
+ ? -5 - (this.$refs.popover as HTMLElement).clientHeight
130
+ : 5;
131
+ this.posY =
132
+ yPosParent +
131
133
  parentScrollTop -
132
134
  parentTop +
133
135
  (this.isFixed ? 0 : window.scrollY) +
@@ -96,7 +96,7 @@ export default defineComponent({
96
96
  percentLiveProgress: { default: 0, type: Number },
97
97
  durationLivePosition: { default: 0, type: Number },
98
98
  listenTime: { default: 0, type: Number },
99
- hlsReady: { default: false , type: Boolean},
99
+ hlsReady: { default: false, type: Boolean },
100
100
  },
101
101
 
102
102
  emits: ["stopPlayer", "update:notListenTime", "changePlayerLargeVersion"],
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <div
3
3
  class="player-container"
4
- :class="playerVideo? 'player-video':''"
4
+ :class="playerVideo ? 'player-video' : ''"
5
5
  :style="{ height: playerHeight }"
6
6
  @transitionend="onHidden"
7
7
  >
8
8
  <template v-if="display">
9
- <PlayerVideo v-if="playerVideo"/>
9
+ <PlayerVideo v-if="playerVideo" />
10
10
  <template v-else>
11
11
  <audio
12
12
  id="audio-player"
@@ -29,7 +29,7 @@
29
29
  :percent-live-progress="percentLiveProgress"
30
30
  :duration-live-position="durationLivePosition"
31
31
  :listen-time="listenTime"
32
- :hlsReady="hlsReady"
32
+ :hls-ready="hlsReady"
33
33
  @stop-player="stopPlayer"
34
34
  @change-player-large-version="playerUpdateLargeVersion(true)"
35
35
  />
@@ -42,7 +42,7 @@
42
42
  :percent-live-progress="percentLiveProgress"
43
43
  :duration-live-position="durationLivePosition"
44
44
  :listen-time="listenTime"
45
- :hlsReady="hlsReady"
45
+ :hls-ready="hlsReady"
46
46
  @stop-player="stopPlayer"
47
47
  @change-player-large-version="playerUpdateLargeVersion(false)"
48
48
  />
@@ -58,16 +58,14 @@ import PlayerLarge from "../player/PlayerLarge.vue";
58
58
  import { usePlayerStore } from "@/stores/PlayerStore";
59
59
  import { mapState, mapActions } from "pinia";
60
60
  import { defineComponent, defineAsyncComponent } from "vue";
61
- const PlayerVideo = defineAsyncComponent(
62
- () => import("./PlayerVideo.vue"),
63
- );
61
+ const PlayerVideo = defineAsyncComponent(() => import("./PlayerVideo.vue"));
64
62
  export default defineComponent({
65
63
  name: "PlayerComponent",
66
64
 
67
65
  components: {
68
66
  PlayerCompact,
69
67
  PlayerLarge,
70
- PlayerVideo
68
+ PlayerVideo,
71
69
  },
72
70
  mixins: [playerLogic],
73
71
  emits: ["hide"],
@@ -93,7 +91,7 @@ export default defineComponent({
93
91
  "playerStatus",
94
92
  "playerHeight",
95
93
  "playerLargeVersion",
96
- "playerVideo"
94
+ "playerVideo",
97
95
  ]),
98
96
  display() {
99
97
  return "STOPPED" !== this.playerStatus;
@@ -129,7 +127,7 @@ export default defineComponent({
129
127
 
130
128
  <style lang="scss">
131
129
  .octopus-app {
132
- .player-container{
130
+ .player-container {
133
131
  max-height: 94%;
134
132
  position: sticky;
135
133
  overflow: hidden;
@@ -118,7 +118,7 @@ export default defineComponent({
118
118
  percentLiveProgress: { default: 0, type: Number },
119
119
  durationLivePosition: { default: 0, type: Number },
120
120
  listenTime: { default: 0, type: Number },
121
- hlsReady: { default: false , type: Boolean},
121
+ hlsReady: { default: false, type: Boolean },
122
122
  },
123
123
 
124
124
  emits: ["stopPlayer", "update:notListenTime", "changePlayerLargeVersion"],
@@ -1,18 +1,13 @@
1
1
  <template>
2
2
  <teleport to=".octopus-app">
3
3
  <template v-if="playerVideo">
4
- <button
4
+ <button
5
5
  class="btn btn-transparent video-close saooti-remove"
6
6
  @click="closePlayer"
7
7
  />
8
8
  <div class="video-wrapper">
9
- <PlayerVideoDigiteka
10
- v-if="!playerLive"
11
- />
12
- <PlayerVideoHls
13
- v-else
14
- :hls-url="hlsUrl"
15
- />
9
+ <PlayerVideoDigiteka v-if="!playerLive" />
10
+ <PlayerVideoHls v-else :hls-url="hlsUrl" />
16
11
  </div>
17
12
  </template>
18
13
  </teleport>
@@ -33,24 +28,24 @@ export default defineComponent({
33
28
 
34
29
  components: {
35
30
  PlayerVideoDigiteka,
36
- PlayerVideoHls
31
+ PlayerVideoHls,
37
32
  },
38
33
  data() {
39
- return {
40
- };
34
+ return {};
41
35
  },
42
36
  computed: {
43
37
  ...mapState(usePlayerStore, ["playerVideo", "playerLive"]),
44
- hlsUrl(): string{
45
- if(!this.playerLive){return "";}
38
+ hlsUrl(): string {
39
+ if (!this.playerLive) {
40
+ return "";
41
+ }
46
42
  return `${state.podcastPage.hlsUri}live/video_dev.${this.playerLive.conferenceId}/index.m3u8`;
47
- //return "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8";
48
- }
43
+ },
49
44
  },
50
45
 
51
46
  methods: {
52
- ...mapActions(usePlayerStore, ["playerPlay",]),
53
- closePlayer(){
47
+ ...mapActions(usePlayerStore, ["playerPlay"]),
48
+ closePlayer() {
54
49
  this.playerPlay();
55
50
  },
56
51
  },
@@ -59,32 +54,32 @@ export default defineComponent({
59
54
 
60
55
  <style lang="scss">
61
56
  .octopus-app {
62
- .video-wrapper{
63
- border-radius: 2rem;
57
+ .video-wrapper {
58
+ border-radius: 1rem;
64
59
  overflow: hidden;
65
60
  position: fixed;
66
61
  bottom: 2.5rem;
67
62
  right: 0;
68
63
  z-index: 10;
69
64
  }
70
- .video-close{
65
+ .video-close {
71
66
  position: fixed;
72
67
  bottom: 16.5rem;
73
68
  right: 1rem;
74
69
  }
75
70
  @media (max-width: 500px) {
76
- .video-wrapper{
77
- position:relative;
78
- padding-bottom:56.25%;
79
- height:0;
71
+ .video-wrapper {
72
+ position: relative;
73
+ padding-bottom: 56.25%;
74
+ height: 0;
80
75
  }
81
76
  .video-wrapper iframe {
82
- position:absolute;
83
- top:0;
84
- left:0;
85
- width:100% !important;
86
- height:100%;
87
- margin:0 !important;
77
+ position: absolute;
78
+ top: 0;
79
+ left: 0;
80
+ width: 100% !important;
81
+ height: 100%;
82
+ margin: 0 !important;
88
83
  }
89
84
  }
90
85
  }
@@ -1,12 +1,13 @@
1
1
  <template>
2
- <iframe
2
+ <iframe
3
3
  ref="iframeVideo"
4
4
  :src="srcVideo"
5
- width="500"
6
- height="281"
7
- style="z-index:1;"
8
- allowfullscreen="true"
9
- allow="autoplay"
5
+ :title="$t('Video')"
6
+ width="500"
7
+ height="281"
8
+ style="z-index: 1"
9
+ allowfullscreen="true"
10
+ allow="autoplay"
10
11
  referrerpolicy="no-referrer-when-downgrade"
11
12
  ></iframe>
12
13
  </template>
@@ -17,32 +18,34 @@ import { mapState } from "pinia";
17
18
  import { defineComponent } from "vue";
18
19
  export default defineComponent({
19
20
  name: "PlayerVideo",
20
- components: {
21
- },
21
+ components: {},
22
22
 
23
- computed:{
24
- ...mapState(usePlayerStore, [
25
- "playerPodcast",
26
- "playerVideo"
27
- ]),
28
- srcVideo(): string{
29
- if(this.playerVideo){
30
- return "//www.ultimedia.com/deliver/generic/iframe/mdtk/01009833/zone/1/showtitle/1/src/"+ this.playerPodcast?.video?.videoId+"/autoplay/1";
23
+ computed: {
24
+ ...mapState(usePlayerStore, ["playerPodcast", "playerVideo"]),
25
+ srcVideo(): string {
26
+ if (this.playerVideo) {
27
+ return (
28
+ "//www.ultimedia.com/deliver/generic/iframe/mdtk/01009833/zone/1/showtitle/1/src/" +
29
+ this.playerPodcast?.video?.videoId +
30
+ "/autoplay/1"
31
+ );
31
32
  }
32
33
  return "";
33
- }
34
+ },
34
35
  },
35
- watch:{
36
+ watch: {
36
37
  srcVideo() {
37
38
  this.goFullScreen();
38
39
  },
39
40
  },
40
- mounted(){
41
+ mounted() {
41
42
  this.goFullScreen();
42
43
  },
43
- methods:{
44
- goFullScreen(){
45
- if(""===this.srcVideo){return;}
44
+ methods: {
45
+ goFullScreen() {
46
+ if ("" === this.srcVideo) {
47
+ return;
48
+ }
46
49
  switch (screen.orientation.type) {
47
50
  case "landscape-primary":
48
51
  case "landscape-secondary":
@@ -55,8 +58,7 @@ export default defineComponent({
55
58
  default:
56
59
  console.log("The orientation API isn't supported in this browser :(");
57
60
  }
58
- }
59
- }
60
-
61
+ },
62
+ },
61
63
  });
62
- </script>
64
+ </script>
@@ -1,24 +1,25 @@
1
1
  <template>
2
- <div class="video-player">
3
- <div v-if="errorPlay.length" class="video-live-error">{{errorPlay}}</div>
2
+ <div id="player-video-hls" class="video-player">
3
+ <div v-if="errorPlay.length" class="video-live-error">{{ errorPlay }}</div>
4
4
  <video
5
- v-show="useVideoSrc"
5
+ id="video-element-hls"
6
6
  ref="videoelement"
7
+ class="video-js"
7
8
  playsinline
8
- />
9
- <div
10
- ref="videocontainer"
11
- class="video-container"
12
- />
9
+ ></video>
13
10
  </div>
14
11
  </template>
15
12
  <script lang="ts">
16
-
17
- // @ts-ignore
18
- import Clappr from '@clappr/core';
19
- // @ts-ignore
20
- import HlsjsPlayback from '@clappr/hlsjs-playback';
21
- import { defineComponent } from 'vue';
13
+ import videojs, { VideoJsPlayer } from "video.js";
14
+ import qualitySelector from "videojs-hls-quality-selector";
15
+ import qualityLevels from "videojs-contrib-quality-levels";
16
+ if (!videojs.getPlugin("qualityLevels")) {
17
+ videojs.registerPlugin("qualityLevels", qualityLevels);
18
+ }
19
+ if (!videojs.getPlugin("hlsQualitySelector")) {
20
+ videojs.registerPlugin("hlsQualitySelector", qualitySelector);
21
+ }
22
+ import { defineComponent } from "vue";
22
23
  export default defineComponent({
23
24
  name: "PlayerVideoHls",
24
25
 
@@ -26,37 +27,62 @@ export default defineComponent({
26
27
  hlsUrl: { default: "", type: String },
27
28
  },
28
29
 
29
- emits:['changeValid'],
30
+ emits: ["changeValid"],
30
31
  data() {
31
32
  return {
32
33
  errorPlay: "" as string,
33
34
  useVideoSrc: false as boolean,
34
- player: undefined as Clappr.Player,
35
+ player: undefined as VideoJsPlayer | undefined,
35
36
  playing: false as boolean,
36
- stalledTimout: undefined as ReturnType<typeof setTimeout>|undefined,
37
+ stalledTimout: undefined as ReturnType<typeof setTimeout> | undefined,
37
38
  };
38
39
  },
39
- computed:{
40
- videoContainer(): HTMLElement{
41
- return (this.$refs.videocontainer as HTMLElement);
40
+ computed: {
41
+ videoElement(): HTMLVideoElement {
42
+ return this.$refs.videoelement as HTMLVideoElement;
42
43
  },
43
- videoElement(): HTMLVideoElement{
44
- return (this.$refs.videoelement as HTMLVideoElement);
44
+ videoOptions() {
45
+ return {
46
+ autoplay: true,
47
+ controls: true,
48
+ liveui: true,
49
+ sources: [
50
+ {
51
+ src: this.hlsUrl,
52
+ type: "application/x-mpegURL",
53
+ },
54
+ ],
55
+ html5: {
56
+ vhs: {
57
+ overrideNative: !videojs.browser.IS_SAFARI,
58
+ },
59
+ nativeAudioTracks: false,
60
+ nativeVideoTracks: false,
61
+ },
62
+ plugins: {
63
+ hlsQualitySelector: {
64
+ displayCurrentQuality: true,
65
+ },
66
+ },
67
+ };
45
68
  },
46
69
  },
47
- mounted(){
70
+ mounted() {
48
71
  this.playLive();
72
+ this.useVideoSrc =
73
+ "" !== this.videoElement.canPlayType("application/vnd.apple.mpegurl") &&
74
+ !navigator.userAgent.includes("Android");
49
75
  },
50
76
 
51
- beforeUnmount() {
52
- if(this.playing){
77
+ beforeUnmount() {
78
+ if (this.playing) {
53
79
  this.stopLive();
54
80
  }
55
81
  },
56
82
 
57
83
  methods: {
58
- definedStalledTimeout(){
59
- this.stalledTimout =setTimeout(()=>{
84
+ definedStalledTimeout() {
85
+ this.stalledTimout = setTimeout(() => {
60
86
  this.videoClean();
61
87
  this.playLive();
62
88
  }, 5000);
@@ -64,99 +90,91 @@ export default defineComponent({
64
90
  async playLive(): Promise<void> {
65
91
  clearTimeout(this.stalledTimout);
66
92
  this.definedStalledTimeout();
67
- if (this.videoElement.canPlayType('application/vnd.apple.mpegurl') && !navigator.userAgent.includes('Android')) {
68
- this.useVideoSrc = true;
93
+ if (this.useVideoSrc) {
69
94
  this.playLiveIos();
70
95
  return;
71
96
  }
72
- this.player = new Clappr.Player({
73
- source: this.hlsUrl,
74
- autoPlay: false,
75
- height: '100%',
76
- width: '100%',
77
- plugins: {
78
- playback: [HlsjsPlayback],
79
- },
80
- playback: {
81
- controls: true,
82
- playInline: true,
83
- hlsjsConfig: {
84
- enableWorker: false,
85
- debug:true,
86
- }
97
+ this.player = videojs(
98
+ document.getElementById("video-element-hls") as Element,
99
+ this.videoOptions,
100
+ () => {
101
+ this.errorPlay = "";
102
+ this.playing = true;
87
103
  },
88
- events: {
89
- onError: async(error: Clappr.error) =>{
90
- this.stopLive();
91
- if (error.description && error.description.includes('403')) {
92
- this.errorPlay = this.$t('Video is unavailable');
93
- }else{
94
- this.errorPlay = this.$t('Podcast play error');
95
- }
96
- },
97
- onPlay:()=>{
98
- this.errorPlay = "";
99
- this.playing = true;
100
- },
101
- onTimeUpdate:()=>{
102
- clearTimeout(this.stalledTimout);
103
- this.definedStalledTimeout();
104
- }
104
+ );
105
+ this.player.on("timeupdate", () => {
106
+ clearTimeout(this.stalledTimout);
107
+ this.definedStalledTimeout();
108
+ });
109
+ this.player.on("error", (error) => {
110
+ this.stopLive();
111
+ if (error.description && error.description.includes("403")) {
112
+ this.errorPlay = this.$t("Video is unavailable");
113
+ } else {
114
+ this.errorPlay = this.$t("Podcast play error");
105
115
  }
106
116
  });
107
- this.playing = true;
108
- this.player.attachTo(this.videoContainer);
109
- if(0!==this.videoContainer.getElementsByTagName("video").length){
110
- this.videoContainer.getElementsByTagName("video")[0].play();
111
- }
112
117
  },
113
- async playLiveIos(): Promise<void>{
114
- this.videoElement.onloadedmetadata = ()=>{
115
- const playPromise = this.videoElement.play();
118
+ async playLiveIos(): Promise<void> {
119
+ this.videoElement.onloadedmetadata = () => {
120
+ const playPromise = this.videoElement.play();
116
121
  if (playPromise !== undefined) {
117
- playPromise.then(() => {
118
- this.errorPlay = "";
119
- this.playing = true;
120
- })
121
- .catch(() => {
122
- this.playing = false;
123
- });
122
+ playPromise
123
+ .then(() => {
124
+ this.errorPlay = "";
125
+ this.playing = true;
126
+ })
127
+ .catch(() => {
128
+ this.playing = false;
129
+ });
124
130
  }
125
131
  };
126
- this.videoElement.onerror = async()=>{
132
+ this.videoElement.onerror = async () => {
127
133
  this.stopLive();
128
- this.errorPlay = this.$t('Podcast play error');
134
+ this.errorPlay = this.$t("Podcast play error");
129
135
  };
130
- this.videoElement.ontimeupdate = async()=>{
131
- clearTimeout(this.stalledTimout);
132
- this.definedStalledTimeout();
136
+ this.videoElement.ontimeupdate = async () => {
137
+ clearTimeout(this.stalledTimout);
138
+ this.definedStalledTimeout();
133
139
  };
134
140
  this.videoElement.src = this.hlsUrl;
135
141
  },
136
- videoClean(): void{
137
- if(this.useVideoSrc){
142
+ videoClean(): void {
143
+ if (this.useVideoSrc) {
138
144
  this.videoElement.pause();
139
- this.videoElement.removeAttribute('src');
145
+ this.videoElement.removeAttribute("src");
140
146
  this.videoElement.load();
141
147
  return;
142
148
  }
143
- this.player.destroy();
149
+ if (this.player) {
150
+ this.player.dispose();
151
+ //Redraw
152
+ const video_parent = document.getElementById("player-video-hls");
153
+ if (video_parent) {
154
+ const video = document.createElement("video");
155
+ video.id = "video-element-hls";
156
+ video.className = "video-js";
157
+ video.preload = "auto";
158
+ video.setAttribute("playsinline", "true");
159
+ video_parent.appendChild(video);
160
+ }
161
+ }
144
162
  },
145
- stopLive(): void{
163
+ stopLive(): void {
146
164
  clearTimeout(this.stalledTimout);
147
165
  this.errorPlay = "";
148
166
  this.videoClean();
149
167
  this.playing = false;
150
168
  },
151
169
  },
152
-
153
170
  });
154
171
  </script>
155
172
 
156
173
  <style lang="scss">
174
+ @import "video.js";
157
175
  @import "@scss/_variables.scss";
158
- .octopus-app{
159
- .video-live-error{
176
+ .octopus-app {
177
+ .video-live-error {
160
178
  text-align: center;
161
179
  width: 100%;
162
180
  font-size: 1rem;
@@ -168,7 +186,7 @@ export default defineComponent({
168
186
  background: $danger;
169
187
  z-index: 1;
170
188
  }
171
- .video-container{
189
+ .video-js {
172
190
  width: 500px;
173
191
  height: 281px;
174
192
  }
@@ -83,24 +83,27 @@ export default defineComponent({
83
83
  this.handleResize(0);
84
84
  },
85
85
  methods: {
86
- handleResize(indexAsked: number): void {
87
- const historyList = this.$refs.historyListContainer as HTMLElement;
88
- if (null === historyList || !historyList) {
89
- return;
90
- }
91
- this.indexStart = indexAsked;
92
- this.indexNotDisplay = this.playerRadioHistory.length;
86
+ displayEverythingAfterIndex(indexAsked: number){
93
87
  for (let index = 0; index < this.playerRadioHistory.length; index++) {
94
88
  const el = (this.$refs["history" + index] as Array<HTMLElement>)[0];
95
89
  if (!el) continue;
96
- if (index < this.indexStart && !el.classList.contains("hid")) {
90
+ if (index < indexAsked && !el.classList.contains("hid")) {
97
91
  el.classList.add("hid");
98
92
  continue;
99
93
  }
100
- if (index >= this.indexStart && el.classList.contains("hid")) {
94
+ if (index >= indexAsked && el.classList.contains("hid")) {
101
95
  el.classList.remove("hid");
102
96
  }
103
97
  }
98
+ },
99
+ handleResize(indexAsked: number): void {
100
+ const historyList = this.$refs.historyListContainer as HTMLElement;
101
+ if (null === historyList || !historyList) {
102
+ return;
103
+ }
104
+ this.indexStart = indexAsked;
105
+ this.indexNotDisplay = this.playerRadioHistory.length;
106
+ this.displayEverythingAfterIndex(indexAsked);
104
107
  for (
105
108
  let index = this.indexStart + 1;
106
109
  index < this.playerRadioHistory.length;
@@ -5,7 +5,7 @@
5
5
  >
6
6
  <div
7
7
  class="octopus-progress-bar"
8
- :class="isBack ? 'no-transition': ''"
8
+ :class="isBack ? 'no-transition' : ''"
9
9
  role="progressbar"
10
10
  aria-valuenow="0"
11
11
  aria-valuemin="0"
@@ -89,7 +89,7 @@ export default defineComponent({
89
89
  .octopus-progress-bar {
90
90
  background-color: #747474;
91
91
  }
92
- .no-transition{
92
+ .no-transition {
93
93
  transition: none !important;
94
94
  }
95
95
  }
@@ -182,7 +182,7 @@ export default defineComponent({
182
182
  "podcastAddict",
183
183
  "playerFm",
184
184
  "pocketCasts",
185
- "iHeart"
185
+ "iHeart",
186
186
  ];
187
187
  let count = 0;
188
188
  for (let i = 0, len = platformShare.length; i < len; i++) {
@@ -200,7 +200,7 @@ export default defineComponent({
200
200
  "podcastAddict",
201
201
  "playerFm",
202
202
  "pocketCasts",
203
- "iHeart"
203
+ "iHeart",
204
204
  ];
205
205
  let count = 0;
206
206
  for (let i = 0, len = platformShare.length; i < len; i++) {
@@ -5,6 +5,7 @@
5
5
  v-model:search-pattern="searchPattern"
6
6
  />
7
7
  <AdvancedSearch
8
+ v-model:only-video="onlyVideo"
8
9
  :is-education="isEducation"
9
10
  :is-emission="false"
10
11
  :reset-rubriquage="resetRubriquage"
@@ -79,6 +80,8 @@ export default defineComponent({
79
80
  noRubriquageId: [] as Array<number>,
80
81
  rubriquageId: [] as Array<number>,
81
82
  rubriqueId: [] as Array<number>,
83
+ //VIDEO_WORK
84
+ onlyVideo: false as boolean,
82
85
  };
83
86
  },
84
87
 
package/src/locale/fr.ts CHANGED
@@ -351,4 +351,8 @@ export default {
351
351
  "List":"Liste",
352
352
  "Display HTML":"Afficher HTML",
353
353
  "Video is unavailable":"La vidéo est indisponible",
354
+
355
+
356
+ "Show only episodes with video":"Afficher uniquement les épisodes avec une vidéo",
357
+ "Video":"Vidéo",
354
358
  };