@saooti/octopus-sdk 29.0.7 → 29.0.11

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.
@@ -0,0 +1,109 @@
1
+ <template>
2
+ <div class="d-flex justify-content-around mt-3 flex-grow w-100">
3
+ <div class="d-flex flex-column align-items-center flex-shrink me-3">
4
+ <div class="fw-600">
5
+ {{ $t('Choose color') }}
6
+ </div>
7
+ <VSwatches
8
+ v-model="internColor"
9
+ class="c-hand input-no-outline"
10
+ show-fallback
11
+ colors="text-advanced"
12
+ popover-to="right"
13
+ :data-color="internColor"
14
+ />
15
+ </div>
16
+ <div class="d-flex flex-column align-items-center">
17
+ <div class="fw-600">
18
+ {{ $t('Choose theme') }}
19
+ </div>
20
+ <div
21
+ v-if="!isBeta"
22
+ class="d-flex"
23
+ >
24
+ <VSwatches
25
+ v-for="myColor in colors"
26
+ :key="myColor"
27
+ v-model="internTheme"
28
+ :data-theme="internTheme"
29
+ class="c-hand input-no-outline me-1"
30
+ :swatch-style="{
31
+ padding: '0px 0px',
32
+ marginRight: '0px',
33
+ marginBottom: '0px',
34
+ border: '1px gray solid',
35
+ }"
36
+ :wrapper-style="{
37
+ paddingTop: '0px',
38
+ paddingLeft: '0px',
39
+ paddingRight: '0px',
40
+ paddingBottom: '0px',
41
+ }"
42
+ :swatches="[myColor]"
43
+ inline
44
+ />
45
+ </div>
46
+ <VSwatches
47
+ v-else
48
+ v-model="internTheme"
49
+ class="c-hand input-no-outline"
50
+ show-fallback
51
+ colors="text-advanced"
52
+ popover-to="right"
53
+ :data-color="internTheme"
54
+ />
55
+ </div>
56
+ </div>
57
+ </template>
58
+
59
+ <script lang="ts">
60
+ import VSwatches from 'vue3-swatches';
61
+ import { defineComponent } from 'vue';
62
+ export default defineComponent({
63
+ components: {
64
+ VSwatches
65
+ },
66
+
67
+ props: {
68
+ isBeta: { default: false, type: Boolean},
69
+ color: { default: '#40a372', type: String},
70
+ theme: { default: '#000000', type: String},
71
+ },
72
+ emits:['update:color', 'update:theme'],
73
+
74
+ data() {
75
+ return {
76
+ internColor:'#40a372' as string,
77
+ internTheme:'#000000' as string,
78
+ colors: ['#000000', '#ffffff'],
79
+ };
80
+ },
81
+ watch:{
82
+ color(){
83
+ if(this.color !== this.internColor){
84
+ this.internColor = this.color;
85
+ }
86
+ },
87
+ internColor(){
88
+ if(this.color !== this.internColor){
89
+ this.$emit('update:color', this.internColor);
90
+ }
91
+ },
92
+ theme(){
93
+ if(this.theme !== this.internTheme){
94
+ this.internTheme = this.theme;
95
+ }
96
+ },
97
+ internTheme(){
98
+ if(this.theme !== this.internTheme){
99
+ this.$emit('update:theme', this.internTheme);
100
+ }
101
+ }
102
+ },
103
+ mounted(){
104
+ this.internColor= this.color;
105
+ this.internTheme= this.theme;
106
+ }
107
+
108
+ })
109
+ </script>
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <div class="d-flex flex-column">
3
+ <label
4
+ for="iframe-select"
5
+ class="d-inline"
6
+ aria-label="select miniplayer"
7
+ />
8
+ <select
9
+ id="iframe-select"
10
+ :value="iFrameModel"
11
+ class="frame-select input-no-outline"
12
+ @change="$emit('update:iFrameModel',$event.target.value)"
13
+ >
14
+ <option value="default">
15
+ {{ $t('Default version') }}
16
+ </option>
17
+ <option value="large">
18
+ {{ $t('Large version') }}
19
+ </option>
20
+ <template v-if="isBeta">
21
+ <option
22
+ v-for="player in customPlayersDisplay"
23
+ :key="player.customId"
24
+ :value="player.customId"
25
+ >
26
+ {{ $t('Custom version') + " «" +player.name+"»" }}
27
+ </option>
28
+ </template>
29
+ <option
30
+ v-if="podcast && podcast.podcastId"
31
+ value="emission"
32
+ >
33
+ {{
34
+ $t('Emission version')
35
+ }}
36
+ </option>
37
+ <option
38
+ v-if="podcast && podcast.podcastId"
39
+ value="largeEmission"
40
+ >
41
+ {{ $t('Large emission version') }}
42
+ </option>
43
+ <option
44
+ v-if="podcast && podcast.podcastId"
45
+ value="largeSuggestion"
46
+ >
47
+ {{ $t('Large suggestion version') }}
48
+ </option>
49
+ </select>
50
+ </div>
51
+ </template>
52
+
53
+ <script lang="ts">
54
+ import { Podcast } from '@/store/class/podcast';
55
+ import { CustomPlayer } from '@/store/class/customPlayer';
56
+ import { defineComponent } from 'vue';
57
+ import { Emission } from '@/store/class/emission';
58
+ import { Playlist } from '@/store/class/playlist';
59
+ export default defineComponent({
60
+ props: {
61
+ podcast: { default: undefined, type: Object as ()=> Podcast},
62
+ emission: { default: undefined, type: Object as ()=> Emission},
63
+ playlist: { default: undefined, type: Object as ()=> Playlist},
64
+ customPlayers: { default: ()=>[], type: Array as ()=> Array<CustomPlayer>},
65
+ isBeta: { default: false, type: Boolean},
66
+ iFrameModel: { default: 'default', type: String},
67
+ },
68
+ emits:['update:iFrameModel'],
69
+
70
+ computed: {
71
+ customPlayersDisplay(): Array<CustomPlayer>{
72
+ return this.customPlayers.filter((player: CustomPlayer)=>{
73
+ return (('EPISODE' === player.typePlayer ||'SUGGESTION' === player.typePlayer) && this.podcast && this.podcast.podcastId) ||
74
+ ('EMISSION' === player.typePlayer && this.emission && !this.podcast)|| ('PLAYLIST' === player.typePlayer && this.playlist );
75
+ });
76
+ },
77
+ },
78
+ })
79
+ </script>
@@ -48,151 +48,53 @@
48
48
  @durationChange="onTimeUpdate"
49
49
  @error="onError"
50
50
  />
51
- <router-link
52
- v-if="isImage && podcastImage"
53
- :to="podcastShareUrl"
54
- >
55
- <img
56
- :src="podcastImage"
57
- :alt="$t('Podcast image')"
58
- class="player-image c-hand"
59
- >
60
- </router-link>
61
-
62
- <div
63
- v-if="!playerError"
64
- class="play-button-box"
65
- :class="{
66
- 'primary-bg': !isLoading,
67
- 'text-light': !isLoading,
68
- }"
69
- @click="switchPausePlay"
70
- >
71
- <div
72
- class="text-light"
73
- :aria-label="$t('Play')"
74
- :class="{
75
- saooti: isPlaying || isPaused,
76
- 'saooti-play2-bounty': isPaused,
77
- 'saooti-pause-bounty': isPlaying,
78
- loading: isLoading,
79
- }"
80
- />
81
- </div>
82
- <div
83
- v-if="(isPlaying || isPaused) && (media || isStop)"
84
- class="play-button-box primary-bg text-light"
85
- @click="stopPlayer"
86
- >
87
- <div
88
- class="text-light saooti-stop-bounty"
89
- :aria-label="$t('Stop')"
90
- />
91
- </div>
92
- <div class="text-light player-grow-content">
93
- <div class="d-flex">
94
- <div
95
- v-if="playerError"
96
- class="text-warning player-title ms-2 me-2"
97
- >
98
- {{ $t('Podcast play error') + ' - ' }}
99
- </div>
100
- <div class="flex-grow player-title">
101
- {{ podcastTitle }}
102
- </div>
103
- <div
104
- v-if="!playerError"
105
- v-show="!isBarTop"
106
- class="hide-phone"
107
- >
108
- {{ playedTime }} / {{ totalTime }}
109
- </div>
110
- </div>
111
- <div
112
- v-if="!playerError"
113
- v-show="!isBarTop"
114
- class="progress c-hand custom-bg-darkgrey"
115
- style="height: 3px;"
116
- @mouseup="seekTo"
117
- >
118
- <div
119
- class="progress-bar custom-bg-grey"
120
- role="progressbar"
121
- aria-valuenow="0"
122
- aria-valuemin="0"
123
- aria-valuemax="100"
124
- :style="'width: ' + percentLiveProgress + '%'"
125
- />
126
- <div
127
- class="progress-bar primary-bg"
128
- role="progressbar"
129
- aria-valuenow="0"
130
- aria-valuemin="0"
131
- aria-valuemax="100"
132
- :style="'width: ' + percentProgress + '%'"
133
- />
134
- <div
135
- v-if="displayAlertBar"
136
- class="progress-bar progress-bar-duration bg-danger"
137
- :style="'left: ' + durationLivePosition + '%'"
138
- />
139
- </div>
140
- <CommentPlayer
141
- v-if="showTimeline"
142
- :total-time="totalSecondes"
143
- :comments="comments"
144
- />
145
- </div>
146
- <div
147
- v-if="0 !== comments.length && !isPodcastmaker"
148
- class="timeline-button"
149
- @click="showTimeline = !showTimeline"
150
- >
151
- <div
152
- class="saooti-arrow_down saooti-arrow_down-margin"
153
- :class="showTimeline ? '' : 'arrow-transform'"
154
- />
155
- <div>Timeline</div>
156
- </div>
157
- <div
158
- v-if="isClock"
159
- class="d-flex text-light align-items-center hide-phone"
160
- >
161
- <div class="saooti-clock-stud m-2" />
162
- <div>{{ actualTime }}</div>
163
- </div>
51
+ <PlayerButtons
52
+ :player-error="playerError"
53
+ />
54
+ <PlayerProgressBar
55
+ v-model:notListenTime="notListenTime"
56
+ :hls-ready="hlsReady"
57
+ :show-timeline="showTimeline"
58
+ :comments="comments"
59
+ :display-alert-bar="displayAlertBar"
60
+ :percent-live-progress="percentLiveProgress"
61
+ :duration-live-position="durationLivePosition"
62
+ :player-error="playerError"
63
+ :listen-time="listenTime"
64
+ />
65
+ <PlayerClockAndTimeline
66
+ v-model:showTimeline="showTimeline"
67
+ :comments="comments"
68
+ />
164
69
  </div>
165
70
  </div>
166
71
  </div>
167
72
  </template>
168
-
169
73
  <script lang="ts">
170
74
  import { mapState } from 'vuex';
171
75
  import { state } from '../../store/paramStore';
172
- import DurationHelper from '../../helper/duration';
173
76
  const octopusApi = require('@saooti/octopus-api');
174
77
  let Hls: any= null;
175
-
176
- const moment = require('moment');
177
- //const axios = require("axios");
178
78
  import { CommentPodcast } from '@/store/class/comment';
179
79
  import { cookies } from '../mixins/functions';
180
80
  import { StoreState } from '@/store/typeAppStore';
181
- import { defineComponent, defineAsyncComponent } from 'vue';
182
- const CommentPlayer = defineAsyncComponent(() => import('../display/comments/CommentPlayer.vue'));
81
+ import PlayerProgressBar from './PlayerProgressBar.vue';
82
+ import PlayerButtons from './PlayerButtons.vue';
83
+ import PlayerClockAndTimeline from './PlayerClockAndTimeline.vue';
84
+ import { defineComponent } from 'vue';
183
85
  export default defineComponent({
184
86
  name: 'Player',
185
87
 
186
88
  components: {
187
- CommentPlayer,
89
+ PlayerProgressBar,
90
+ PlayerButtons,
91
+ PlayerClockAndTimeline
188
92
  },
189
93
  mixins:[cookies],
190
94
  emits: ['hide'],
191
-
192
95
  data() {
193
96
  return {
194
97
  forceHide: false as boolean,
195
- actualTime: '' as string,
196
98
  listenTime: 0 as number,
197
99
  notListenTime: 0 as number,
198
100
  lastSend: 0 as number,
@@ -207,29 +109,7 @@ export default defineComponent({
207
109
  showTimeline: false as boolean,
208
110
  };
209
111
  },
210
-
211
112
  computed: {
212
- isPodcastmaker(): boolean {
213
- return state.generalParameters.podcastmaker;
214
- },
215
- isPlaying(): boolean {
216
- return 'PLAYING' === this.status;
217
- },
218
- isPaused(): boolean {
219
- return 'PAUSED' === this.status;
220
- },
221
- isLoading(): boolean {
222
- return 'LOADING' === this.status;
223
- },
224
- isImage(): string {
225
- return state.player.image;
226
- },
227
- isEmissionName(): string {
228
- return state.player.emissionName;
229
- },
230
- isClock(): boolean {
231
- return state.player.clock;
232
- },
233
113
  isBarTop(): boolean {
234
114
  return state.player.barTop;
235
115
  },
@@ -241,35 +121,15 @@ export default defineComponent({
241
121
  if (window.innerWidth > 450 && this.showTimeline) return '6rem';
242
122
  return '3.5rem';
243
123
  },
244
- status: (state: StoreState) => state.player.status,
245
124
  podcast: (state: StoreState) => state.player.podcast,
246
125
  media: (state: StoreState) => state.player.media,
247
126
  live: (state: StoreState) => state.player.live,
248
127
  volume: (state: StoreState) => state.player.volume,
249
- isStop: (state: StoreState) => state.player.stop,
250
128
  commentsLoaded: (state: StoreState) => state.comments.loadedComments,
251
- podcastImage: (state: StoreState) => {
252
- if (state.player.podcast) return state.player.podcast.imageUrl;
253
- return '';
254
- },
255
- playedTime: (state: StoreState) => {
256
- if (state.player.elapsed && state.player.elapsed > 0 && state.player.total && state.player.total > 0) {
257
- return DurationHelper.formatDuration(
258
- Math.round(state.player.elapsed * state.player.total)
259
- );
260
- }
261
- return '--:--';
262
- },
263
129
  percentProgress: (state: StoreState) => {
264
130
  if(!state.player.elapsed){return 0;}
265
131
  return state.player.elapsed * 100;
266
132
  },
267
- totalTime: (state: StoreState) => {
268
- if (state.player.elapsed && state.player.elapsed > 0 && state.player.total && state.player.total > 0)
269
- return DurationHelper.formatDuration(Math.round(state.player.total));
270
- return '--:--';
271
- },
272
- totalSecondes: (state: StoreState) => state.player.total,
273
133
  }),
274
134
  audioUrl(): string {
275
135
  if (this.media) return this.media.audioUrl;
@@ -291,34 +151,6 @@ export default defineComponent({
291
151
  }
292
152
  return this.podcast.audioUrl + '?' + parameters.join('&');
293
153
  },
294
- podcastShareUrl(): any {
295
- if (this.podcast) {
296
- return {
297
- name: 'podcast',
298
- params: { podcastId: this.podcast.podcastId },
299
- query: { productor: this.$store.state.filter.organisationId },
300
- };
301
- }
302
- return '';
303
- },
304
- podcastTitle(): string {
305
- if (this.podcast) {
306
- if (this.isEmissionName)
307
- return this.emissionName + ' - ' + this.podcast.title;
308
- return this.podcast.title;
309
- }
310
- if (this.media) return this.media.title;
311
- if (this.live) {
312
- if (!this.hlsReady)
313
- return this.live.title + ' (' + this.$t('Start in a while') + ')';
314
- return this.live.title;
315
- }
316
- return '';
317
- },
318
- emissionName(): string {
319
- if (this.podcast) return this.podcast.emission.name;
320
- return '';
321
- },
322
154
  organisationId(): string {
323
155
  return state.generalParameters.organisationId;
324
156
  },
@@ -347,16 +179,7 @@ export default defineComponent({
347
179
  }
348
180
  },
349
181
  async listenTime(newVal): Promise<void> {
350
- if (!this.podcast && !this.live) {
351
- //Nothing can be done there is no listen time
352
- return;
353
- }
354
- if (!this.getDownloadId()) {
355
- //nothing can be done there is no downloadId
356
- return;
357
- }
358
- if (newVal - this.lastSend < 10) {
359
- //Last send is too recent, do nothing
182
+ if ((!this.podcast && !this.live)||(!this.getDownloadId())||(newVal - this.lastSend < 10)) {
360
183
  return;
361
184
  }
362
185
  this.lastSend = newVal;
@@ -371,12 +194,6 @@ export default defineComponent({
371
194
  },
372
195
 
373
196
  mounted() {
374
- moment.locale('fr');
375
- if (this.isClock) {
376
- setInterval(() => {
377
- this.actualTime = moment(new Date()).format('HH:mm:ss');
378
- }, 1000);
379
- }
380
197
  window.addEventListener('beforeunload', this.endListeningProgress);
381
198
  this.watchPlayerStatus();
382
199
  },
@@ -428,30 +245,6 @@ export default defineComponent({
428
245
  this.playerError = true;
429
246
  }
430
247
  },
431
- switchPausePlay(): void {
432
- const audioPlayer: any = document.querySelector('#audio-player');
433
- if (audioPlayer.paused) {
434
- this.onPlay();
435
- } else {
436
- this.onPause();
437
- }
438
- },
439
- stopPlayer(): void {
440
- this.$store.commit('playerPlayPodcast');
441
- },
442
- seekTo(event: { currentTarget: { getBoundingClientRect: () => any; clientWidth: any }; clientX: number }): void {
443
- const audioPlayer: any = document.querySelector('#audio-player');
444
- const rect = event.currentTarget.getBoundingClientRect();
445
- const barWidth = event.currentTarget.clientWidth;
446
- const x = event.clientX - rect.left; //x position within the element.
447
- const percentPosition = x / barWidth;
448
- if (percentPosition * 100 >= this.percentLiveProgress) return;
449
- const seekTime = this.$store.state.player.total * percentPosition;
450
- if (this.podcast || this.live) {
451
- this.notListenTime = seekTime - this.listenTime;
452
- }
453
- audioPlayer.currentTime = seekTime;
454
- },
455
248
  onTimeUpdate(event: { currentTarget: { currentTime: number; duration: any } }): void {
456
249
  if (this.podcast || this.live) {
457
250
  if (!this.getDownloadId()) {
@@ -500,9 +293,6 @@ export default defineComponent({
500
293
  onPlay(): void {
501
294
  this.$store.commit('playerPause', false);
502
295
  },
503
- onPause(): void {
504
- this.$store.commit('playerPause', true);
505
- },
506
296
  onFinished(): void {
507
297
  this.setDownloadId(null);
508
298
  if (this.live) {
@@ -673,21 +463,6 @@ export default defineComponent({
673
463
  </script>
674
464
 
675
465
  <style lang="scss">
676
- @import '../../sass/_variables.scss';
677
-
678
- .play-button-box {
679
- height: 2.5rem;
680
- width: 2.5rem;
681
- display: flex;
682
- align-items: center;
683
- justify-content: center;
684
- margin: 0 0.5rem;
685
- border-radius: 50%;
686
- font-size: 1.2rem;
687
- flex-shrink: 0;
688
- cursor: pointer;
689
- }
690
-
691
466
  .player-container {
692
467
  position: fixed;
693
468
  overflow: hidden;
@@ -701,89 +476,12 @@ export default defineComponent({
701
476
  max-width: 100%;
702
477
  font-size: 1rem;
703
478
 
704
- .player-image {
705
- border-radius: 0.2rem;
706
- height: 2.4rem;
707
- width: 2.4rem;
708
- }
709
479
  .player-progress-border {
710
480
  height: 10px;
711
481
  width: 3px;
712
482
  background: black;
713
483
  }
714
- .progress {
715
- align-items: flex-end;
716
- height: 10px;
717
- position: relative;
718
- }
719
- .progress-bar-duration {
720
- width: 10px;
721
- }
722
- .progress-bar {
723
- height: 4px;
724
- position: absolute;
725
- }
726
-
727
- .progress.custom-bg-darkgrey {
728
- background: #555;
729
- }
730
-
731
- .progress-bar.custom-bg-grey {
732
- background: #e9ecef;
733
- }
734
-
735
- .player-title,
736
- .hide-phone {
737
- font-size: 0.8rem;
738
- margin: 0 0 5px 0;
739
- }
740
- .player-grow-content {
741
- display: flex;
742
- flex-grow: 1;
743
- flex-direction: column;
744
- flex-shrink: 1;
745
- flex-basis: 20px;
746
- overflow: hidden;
747
- }
748
- .player-title {
749
- font-size: 0.8rem;
750
- margin: 0 0 5px 0;
751
- }
752
-
753
- .hide-phone {
754
- font-size: 0.8rem;
755
- margin: 0 0 5px 0;
756
- }
757
- .timeline-button {
758
- background: black;
759
- padding: 0.1rem;
760
- border-radius: 50%;
761
- width: 70px;
762
- height: 70px;
763
- font-size: 0.7rem;
764
- font-weight: bold;
765
- justify-content: center;
766
- display: flex;
767
- flex-direction: column;
768
- align-items: center;
769
- cursor: pointer;
770
- color: $octopus-primary-color;
771
- margin-left: 0.5rem;
772
- @media (max-width: 960px) {
773
- display: none;
774
- }
775
- }
776
484
  }
777
- /** PHONES*/
778
- @media (max-width: 450px) {
779
- .player-container {
780
- .player-image {
781
- height: 2rem;
782
- width: 2rem;
783
- }
784
- }
785
- }
786
-
787
485
  @media (max-width: 960px) {
788
486
  .player-container {
789
487
  .d-flex {
@@ -791,12 +489,6 @@ export default defineComponent({
791
489
  flex-wrap: nowrap !important;
792
490
  }
793
491
  }
794
- .player-title {
795
- font-size: 12px;
796
- overflow: hidden;
797
- white-space: nowrap;
798
- text-overflow: ellipsis;
799
- }
800
492
  }
801
493
  }
802
494
  </style>