@saooti/octopus-sdk 37.0.16 → 37.0.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saooti/octopus-sdk",
3
- "version": "37.0.16",
3
+ "version": "37.0.18",
4
4
  "private": false,
5
5
  "description": "Javascript SDK for using octopus",
6
6
  "author": "Saooti",
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@popperjs/core": "^2.11.8",
18
- "@saooti/octopus-api": "^0.34.3",
18
+ "@saooti/octopus-api": "^0.36.0",
19
19
  "@tiptap/extension-link": "^2.0.4",
20
20
  "@tiptap/extension-underline": "^2.0.4",
21
21
  "@tiptap/pm": "^2.0.4",
@@ -38,6 +38,9 @@
38
38
  "sass": "^1.63.6",
39
39
  "sonarqube-scanner": "^3.0.0",
40
40
  "swiper": "^10.0.4",
41
+ "video.js": "^7.21.5",
42
+ "videojs-contrib-quality-levels": "^2.2.1",
43
+ "videojs-hls-quality-selector": "^1.1.4",
41
44
  "vite": "^4.4.4",
42
45
  "vue": "^3.3.4",
43
46
  "vue-i18n": "^9.2.2",
@@ -48,6 +51,8 @@
48
51
  "vue3-swatches": "^1.2.3"
49
52
  },
50
53
  "devDependencies": {
54
+ "@types/videojs-contrib-quality-levels": "^2.0.1",
55
+ "@types/videojs-hls-quality-selector": "^1.1.0",
51
56
  "@types/vue-select": "^3.16.2",
52
57
  "@typescript-eslint/eslint-plugin": "^6.0.0",
53
58
  "@typescript-eslint/parser": "^6.0.0",
@@ -51,6 +51,15 @@
51
51
  :label="textNotValidate"
52
52
  />
53
53
  </div>
54
+ <ClassicCheckbox
55
+ v-if="!isEmission"
56
+ :textInit="onlyVideo"
57
+ class="flex-shrink-0 mt-3"
58
+ id-checkbox="only-video-checkbox"
59
+ :label="$t('Show only episodes with video')"
60
+ @update:textInit="$emit('update:onlyVideo', $event)"
61
+ />
62
+
54
63
  </div>
55
64
  <div class="d-flex flex-column">
56
65
  <div class="text-primary mb-2">
@@ -96,6 +105,7 @@ export default defineComponent({
96
105
  isEducation: { default: false, type: Boolean },
97
106
  includeHidden: { default: false, type: Boolean },
98
107
  sortCriteria: { default: "DATE", type: String },
108
+ onlyVideo: { default: false, type: Boolean },
99
109
  },
100
110
 
101
111
  emits: [
@@ -107,6 +117,7 @@ export default defineComponent({
107
117
  "includeHidden",
108
118
  "notValid",
109
119
  "updateRubriquageFilter",
120
+ "update:onlyVideo"
110
121
  ],
111
122
  data() {
112
123
  return {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="position-relative">
2
+ <div class="position-relative w-100">
3
3
  <template v-if="!isPhone">
4
4
  <button class="btn-transparent swiper-button-prev" v-show="isLoop" @click="slidePrevButton()"></button>
5
5
  <swiper
@@ -110,7 +110,7 @@ export default defineComponent({
110
110
  "playerVideo"
111
111
  ]),
112
112
  isVideoPodcast(): boolean{
113
- return undefined!==this.podcast.video?.videoId;
113
+ return this.fetchConference?.videoProfile?.includes('video_') || undefined!==this.podcast.video?.videoId;
114
114
  },
115
115
  playingPodcast() {
116
116
  return (
@@ -271,7 +271,7 @@ export default defineComponent({
271
271
  this.playerPlay({
272
272
  ...this.podcast,
273
273
  ...{ conferenceId: this.fetchConference?.conferenceId },
274
- });
274
+ }, isVideo);
275
275
  }
276
276
  if (this.clickPlayGoPage) {
277
277
  this.$router.push("/main/pub/podcast/" + this.podcast.podcastId);
@@ -6,10 +6,7 @@
6
6
  @transitionend="onHidden"
7
7
  >
8
8
  <template v-if="display">
9
- <PlayerVideo
10
- v-if="playerVideo"
11
- @close="closePlayer"
12
- />
9
+ <PlayerVideo v-if="playerVideo"/>
13
10
  <template v-else>
14
11
  <audio
15
12
  id="audio-player"
@@ -62,7 +59,7 @@ import { usePlayerStore } from "@/stores/PlayerStore";
62
59
  import { mapState, mapActions } from "pinia";
63
60
  import { defineComponent, defineAsyncComponent } from "vue";
64
61
  const PlayerVideo = defineAsyncComponent(
65
- () => import("../player/PlayerVideo.vue"),
62
+ () => import("./PlayerVideo.vue"),
66
63
  );
67
64
  export default defineComponent({
68
65
  name: "PlayerComponent",
@@ -121,9 +118,6 @@ export default defineComponent({
121
118
  this.forceHide = false;
122
119
  }
123
120
  },
124
- closePlayer(){
125
- this.playerPlay();
126
- },
127
121
  onPause() {
128
122
  if ("PLAYING" === this.playerStatus) {
129
123
  this.playerChangeStatus(true);
@@ -3,78 +3,64 @@
3
3
  <template v-if="playerVideo">
4
4
  <button
5
5
  class="btn btn-transparent video-close saooti-remove"
6
- @click="$emit('close')"
6
+ @click="closePlayer"
7
7
  />
8
8
  <div class="video-wrapper">
9
- <iframe
10
- ref="iframeVideo"
11
- :src="srcVideo"
12
- width="500"
13
- height="281"
14
- style="z-index:1;"
15
- allowfullscreen="true"
16
- allow="autoplay"
17
- referrerpolicy="no-referrer-when-downgrade"
18
- ></iframe>
9
+ <PlayerVideoDigiteka
10
+ v-if="!playerLive"
11
+ />
12
+ <PlayerVideoHls
13
+ v-else
14
+ :hls-url="hlsUrl"
15
+ />
19
16
  </div>
20
17
  </template>
21
18
  </teleport>
22
19
  </template>
23
-
24
20
  <script lang="ts">
21
+ import { state } from "../../../stores/ParamSdkStore";
25
22
  import { usePlayerStore } from "@/stores/PlayerStore";
26
- import { mapState } from "pinia";
27
- import { defineComponent } from "vue";
23
+ import { mapState, mapActions } from "pinia";
24
+ import { defineComponent, defineAsyncComponent } from "vue";
25
+ const PlayerVideoDigiteka = defineAsyncComponent(
26
+ () => import("./PlayerVideoDigiteka.vue"),
27
+ );
28
+ const PlayerVideoHls = defineAsyncComponent(
29
+ () => import("./PlayerVideoHls.vue"),
30
+ );
28
31
  export default defineComponent({
29
32
  name: "PlayerVideo",
33
+
30
34
  components: {
35
+ PlayerVideoDigiteka,
36
+ PlayerVideoHls
31
37
  },
32
- emits:['close'],
33
-
34
- computed:{
35
- ...mapState(usePlayerStore, [
36
- "playerPodcast",
37
- "playerVideo"
38
- ]),
39
- srcVideo(): string{
40
- if(this.playerVideo){
41
- return "//www.ultimedia.com/deliver/generic/iframe/mdtk/01009833/zone/1/showtitle/1/src/"+ this.playerPodcast?.video?.videoId+"/autoplay/1";
42
- }
43
- return "";
38
+ data() {
39
+ return {
40
+ };
41
+ },
42
+ computed: {
43
+ ...mapState(usePlayerStore, ["playerVideo", "playerLive"]),
44
+ hlsUrl(): string{
45
+ if(!this.playerLive){return "";}
46
+ 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";
44
48
  }
45
49
  },
46
- watch:{
47
- srcVideo() {
48
- this.goFullScreen();
50
+
51
+ methods: {
52
+ ...mapActions(usePlayerStore, ["playerPlay",]),
53
+ closePlayer(){
54
+ this.playerPlay();
49
55
  },
50
56
  },
51
- mounted(){
52
- this.goFullScreen();
53
- },
54
- methods:{
55
- goFullScreen(){
56
- if(""===this.srcVideo){return;}
57
- switch (screen.orientation.type) {
58
- case "landscape-primary":
59
- case "landscape-secondary":
60
- (this.$refs.iframeVideo as Element).requestFullscreen();
61
- break;
62
- case "portrait-secondary":
63
- case "portrait-primary":
64
- console.log("Portrait mode");
65
- break;
66
- default:
67
- console.log("The orientation API isn't supported in this browser :(");
68
- }
69
- }
70
- }
71
-
72
57
  });
73
58
  </script>
59
+
74
60
  <style lang="scss">
75
61
  .octopus-app {
76
62
  .video-wrapper{
77
- border-radius: 2rem;
63
+ border-radius: 1rem;
78
64
  overflow: hidden;
79
65
  position: fixed;
80
66
  bottom: 2.5rem;
@@ -85,7 +71,6 @@ export default defineComponent({
85
71
  position: fixed;
86
72
  bottom: 16.5rem;
87
73
  right: 1rem;
88
-
89
74
  }
90
75
  @media (max-width: 500px) {
91
76
  .video-wrapper{
@@ -103,4 +88,4 @@ export default defineComponent({
103
88
  }
104
89
  }
105
90
  }
106
- </style>
91
+ </style>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <iframe
3
+ ref="iframeVideo"
4
+ :src="srcVideo"
5
+ width="500"
6
+ height="281"
7
+ style="z-index:1;"
8
+ allowfullscreen="true"
9
+ allow="autoplay"
10
+ referrerpolicy="no-referrer-when-downgrade"
11
+ ></iframe>
12
+ </template>
13
+
14
+ <script lang="ts">
15
+ import { usePlayerStore } from "@/stores/PlayerStore";
16
+ import { mapState } from "pinia";
17
+ import { defineComponent } from "vue";
18
+ export default defineComponent({
19
+ name: "PlayerVideo",
20
+ components: {
21
+ },
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";
31
+ }
32
+ return "";
33
+ }
34
+ },
35
+ watch:{
36
+ srcVideo() {
37
+ this.goFullScreen();
38
+ },
39
+ },
40
+ mounted(){
41
+ this.goFullScreen();
42
+ },
43
+ methods:{
44
+ goFullScreen(){
45
+ if(""===this.srcVideo){return;}
46
+ switch (screen.orientation.type) {
47
+ case "landscape-primary":
48
+ case "landscape-secondary":
49
+ (this.$refs.iframeVideo as Element).requestFullscreen();
50
+ break;
51
+ case "portrait-secondary":
52
+ case "portrait-primary":
53
+ console.log("Portrait mode");
54
+ break;
55
+ default:
56
+ console.log("The orientation API isn't supported in this browser :(");
57
+ }
58
+ }
59
+ }
60
+
61
+ });
62
+ </script>
@@ -0,0 +1,183 @@
1
+ <template>
2
+ <div id="player-video-hls" class="video-player">
3
+ <div v-if="errorPlay.length" class="video-live-error">{{errorPlay}}</div>
4
+ <video id="video-element-hls" ref="videoelement" class="video-js" playsinline></video>
5
+ </div>
6
+ </template>
7
+ <script lang="ts">
8
+ import videojs, { VideoJsPlayer } from 'video.js';
9
+ import qualitySelector from 'videojs-hls-quality-selector';
10
+ import qualityLevels from 'videojs-contrib-quality-levels';
11
+ if (!videojs.getPlugin('qualityLevels')) {
12
+ videojs.registerPlugin('qualityLevels', qualityLevels);
13
+ }
14
+ if (!videojs.getPlugin('hlsQualitySelector')) {
15
+ videojs.registerPlugin('hlsQualitySelector', qualitySelector);
16
+ }
17
+ import { defineComponent } from 'vue';
18
+ export default defineComponent({
19
+ name: "PlayerVideoHls",
20
+
21
+ props: {
22
+ hlsUrl: { default: "", type: String },
23
+ },
24
+
25
+ emits:['changeValid'],
26
+ data() {
27
+ return {
28
+ errorPlay: "" as string,
29
+ useVideoSrc: false as boolean,
30
+ player: undefined as VideoJsPlayer|undefined,
31
+ playing: false as boolean,
32
+ stalledTimout: undefined as ReturnType<typeof setTimeout>|undefined,
33
+ };
34
+ },
35
+ computed:{
36
+ videoElement(): HTMLVideoElement{
37
+ return (this.$refs.videoelement as HTMLVideoElement);
38
+ },
39
+ videoOptions(){
40
+ return {
41
+ autoplay: true,
42
+ controls: true,
43
+ liveui: true,
44
+ sources: [
45
+ {
46
+ src: this.hlsUrl,
47
+ type: 'application/x-mpegURL',
48
+ }
49
+ ],
50
+ html5: {
51
+ vhs: {
52
+ overrideNative: !videojs.browser.IS_SAFARI,
53
+ },
54
+ nativeAudioTracks: false,
55
+ nativeVideoTracks: false,
56
+ },
57
+ plugins: {
58
+ hlsQualitySelector: {
59
+ displayCurrentQuality: true,
60
+ },
61
+ },
62
+ }
63
+ }
64
+ },
65
+ mounted(){
66
+ this.playLive();
67
+ this.useVideoSrc = ""!==this.videoElement.canPlayType('application/vnd.apple.mpegurl') && !navigator.userAgent.includes('Android');
68
+ },
69
+
70
+ beforeUnmount() {
71
+ if(this.playing){
72
+ this.stopLive();
73
+ }
74
+ },
75
+
76
+ methods: {
77
+ definedStalledTimeout(){
78
+ this.stalledTimout =setTimeout(()=>{
79
+ this.videoClean();
80
+ this.playLive();
81
+ }, 5000);
82
+ },
83
+ async playLive(): Promise<void> {
84
+ clearTimeout(this.stalledTimout);
85
+ this.definedStalledTimeout();
86
+ if (this.useVideoSrc) {
87
+ this.playLiveIos();
88
+ return;
89
+ }
90
+ this.player = videojs((document.getElementById("video-element-hls") as Element), this.videoOptions, () => {
91
+ this.errorPlay = "";
92
+ this.playing = true;
93
+ });
94
+ this.player.on('timeupdate', () => {
95
+ clearTimeout(this.stalledTimout);
96
+ this.definedStalledTimeout();
97
+ });
98
+ this.player.on('error', (error) => {
99
+ this.stopLive();
100
+ if (error.description && error.description.includes('403')) {
101
+ this.errorPlay = this.$t('Video is unavailable');
102
+ }else{
103
+ this.errorPlay = this.$t('Podcast play error');
104
+ }
105
+ });
106
+ },
107
+ async playLiveIos(): Promise<void>{
108
+ this.videoElement.onloadedmetadata = ()=>{
109
+ const playPromise = this.videoElement.play();
110
+ if (playPromise !== undefined) {
111
+ playPromise.then(() => {
112
+ this.errorPlay = "";
113
+ this.playing = true;
114
+ })
115
+ .catch(() => {
116
+ this.playing = false;
117
+ });
118
+ }
119
+ };
120
+ this.videoElement.onerror = async()=>{
121
+ this.stopLive();
122
+ this.errorPlay = this.$t('Podcast play error');
123
+ };
124
+ this.videoElement.ontimeupdate = async()=>{
125
+ clearTimeout(this.stalledTimout);
126
+ this.definedStalledTimeout();
127
+ };
128
+ this.videoElement.src = this.hlsUrl;
129
+ },
130
+ videoClean(): void{
131
+ if(this.useVideoSrc){
132
+ this.videoElement.pause();
133
+ this.videoElement.removeAttribute('src');
134
+ this.videoElement.load();
135
+ return;
136
+ }
137
+ if(this.player){
138
+ this.player.dispose();
139
+ //Redraw
140
+ const video_parent = document.getElementById("player-video-hls");
141
+ if(video_parent){
142
+ const video = document.createElement('video');
143
+ video.id="video-element-hls";
144
+ video.className="video-js";
145
+ video.preload="auto";
146
+ video.setAttribute("playsinline","true");
147
+ video_parent.appendChild(video);
148
+ }
149
+ }
150
+ },
151
+ stopLive(): void{
152
+ clearTimeout(this.stalledTimout);
153
+ this.errorPlay = "";
154
+ this.videoClean();
155
+ this.playing = false;
156
+ },
157
+ },
158
+
159
+ });
160
+ </script>
161
+
162
+ <style lang="scss">
163
+ @import 'video.js';
164
+ @import "@scss/_variables.scss";
165
+ .octopus-app{
166
+ .video-live-error{
167
+ text-align: center;
168
+ width: 100%;
169
+ font-size: 1rem;
170
+ font-weight: bold;
171
+ padding: 0.2rem 0;
172
+ color: white;
173
+ position: absolute;
174
+ top: 0;
175
+ background: $danger;
176
+ z-index: 1;
177
+ }
178
+ .video-js{
179
+ width: 500px;
180
+ height: 281px;
181
+ }
182
+ }
183
+ </style>
@@ -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/de.ts CHANGED
@@ -343,4 +343,5 @@ export default {
343
343
  "UnorderedList":"Ungeordnete Liste",
344
344
  "List":"Aufführen",
345
345
  "Display HTML":"HTML anzeigen",
346
+ "Video is unavailable":"Video ist nicht verfügbar",
346
347
  };
package/src/locale/en.ts CHANGED
@@ -343,4 +343,5 @@ export default {
343
343
  "UnorderedList":"Unordered list",
344
344
  "List":"List",
345
345
  "Display HTML":"Display HTML",
346
+ "Video is unavailable":"Video is unavailable",
346
347
  };
package/src/locale/es.ts CHANGED
@@ -344,4 +344,5 @@ export default {
344
344
  "UnorderedList":"Lista desordenada",
345
345
  "List":"Lista",
346
346
  "Display HTML":"Mostrar HTML",
347
+ "Video is unavailable":"El vídeo no está disponible",
347
348
  };
package/src/locale/fr.ts CHANGED
@@ -350,4 +350,8 @@ export default {
350
350
  "UnorderedList":"Liste non ordonnée",
351
351
  "List":"Liste",
352
352
  "Display HTML":"Afficher HTML",
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",
353
357
  };
package/src/locale/it.ts CHANGED
@@ -338,4 +338,5 @@ export default {
338
338
  "UnorderedList":"Lista non ordinata",
339
339
  "List":"Elenco",
340
340
  "Display HTML":"Visualizza HTML",
341
+ "Video is unavailable":"Il video non è disponibile",
341
342
  };
package/src/locale/sl.ts CHANGED
@@ -333,4 +333,5 @@ export default {
333
333
  "UnorderedList":"Neurejen seznam",
334
334
  "List":"Seznam",
335
335
  "Display HTML":"Prikaži HTML",
336
+ "Video is unavailable":"Videoposnetek ni na voljo",
336
337
  };
@@ -106,7 +106,7 @@ export const usePlayerStore = defineStore("PlayerStore", {
106
106
  (this.playerPodcast &&
107
107
  this.playerPodcast.podcastId === param.podcastId && isVideo === this.playerVideo) ||
108
108
  (this.playerMedia && this.playerMedia.mediaId === param.mediaId) ||
109
- (this.playerLive && this.playerLive.conferenceId === param.conferenceId)
109
+ (this.playerLive && this.playerLive.conferenceId === param.conferenceId && isVideo === this.playerVideo)
110
110
  ) {
111
111
  //Do nothing
112
112
  return;
@@ -33,4 +33,5 @@ export interface Conference {
33
33
  websocket?: string;
34
34
  interval?: ReturnType<typeof setTimeout>;
35
35
  duration?: number;
36
+ videoProfile?:string;
36
37
  }