@saooti/octopus-sdk 31.0.19 → 31.0.20

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,97 @@
1
+
2
+ import { mapState } from 'vuex';
3
+ import { state } from '../../../store/paramStore';
4
+ import octopusApi from '@saooti/octopus-api';
5
+ import { CommentPodcast } from '@/store/class/general/comment';
6
+ import { StoreState } from '@/store/typeAppStore';
7
+ import { defineComponent } from 'vue';
8
+ import { FetchParam } from '@/store/class/general/fetchParam';
9
+ export const playerComment = defineComponent({
10
+ data() {
11
+ return {
12
+ comments: [] as Array<CommentPodcast>,
13
+ };
14
+ },
15
+ computed: {
16
+ ...mapState({
17
+ commentsLoaded(state: StoreState){ return state.comments.loadedComments},
18
+ live(state: StoreState) { return state.player.live},
19
+ podcast(state: StoreState) { return state.player.podcast}
20
+ }),
21
+ organisationId(): string|undefined {
22
+ return state.generalParameters.organisationId;
23
+ },
24
+ },
25
+
26
+ watch: {
27
+ commentsLoaded(): void {
28
+ this.initComments(true);
29
+ },
30
+ },
31
+ methods: {
32
+ editRight(organisation: string): boolean {
33
+ if (
34
+ (state.generalParameters.isCommments &&
35
+ this.organisationId === organisation) ||
36
+ state.generalParameters.isAdmin
37
+ )
38
+ return true;
39
+ return false;
40
+ },
41
+ async initComments(refresh = false): Promise<void> {
42
+ let podcastId, organisation;
43
+ if (this.podcast) {
44
+ podcastId = this.podcast.podcastId;
45
+ organisation = this.podcast.organisation.id;
46
+ } else if (this.live) {
47
+ podcastId = this.live.livePodcastId;
48
+ organisation = this.live.organisation.id;
49
+ }
50
+ if (
51
+ refresh &&
52
+ podcastId &&
53
+ this.$store.state.comments.actualPodcastId !== podcastId
54
+ ) {
55
+ return;
56
+ }
57
+ let first = 0;
58
+ let count = 0;
59
+ const size = 50;
60
+ if (
61
+ podcastId &&
62
+ this.$store.state.comments.actualPodcastId === podcastId
63
+ ) {
64
+ this.comments = this.commentsLoaded;
65
+ if (
66
+ this.commentsLoaded &&
67
+ this.commentsLoaded.length < this.$store.state.comments.totalCount
68
+ ) {
69
+ first = this.commentsLoaded.length;
70
+ count = this.$store.state.comments.totalCount;
71
+ }
72
+ }
73
+ if (
74
+ (!podcastId ||
75
+ this.$store.state.comments.actualPodcastId === podcastId) &&
76
+ 0 === first
77
+ )
78
+ return;
79
+ while (0 === first || this.comments.length < count) {
80
+ const param: FetchParam = {
81
+ first: first,
82
+ size: size,
83
+ podcastId: podcastId,
84
+ };
85
+ if (!this.editRight(organisation? organisation : '')) {
86
+ param.status = ['Valid'];
87
+ }
88
+ const data = await octopusApi.fetchRootComments(param);
89
+ first += size;
90
+ count = data.totalElements;
91
+ this.comments = this.comments.concat(data.content).filter((c: CommentPodcast) => {
92
+ return null !== c;
93
+ });
94
+ }
95
+ },
96
+ },
97
+ })
@@ -0,0 +1,113 @@
1
+ import { Podcast } from '@/store/class/general/podcast';
2
+ import DurationHelper from '../../../helper/duration';
3
+ import { state } from '@/store/paramStore';
4
+ import { defineComponent } from 'vue';
5
+ import { RouteLocationRaw } from 'vue-router';
6
+ export const playerDisplay = defineComponent({
7
+ props: {
8
+ hlsReady: { default: false , type: Boolean},
9
+ },
10
+ computed:{
11
+ playedTime(): string{
12
+ if (this.$store.state.player.elapsed && this.$store.state.player.elapsed > 0 && this.$store.state.player.total && this.$store.state.player.total > 0) {
13
+ return DurationHelper.formatDuration(
14
+ Math.round(this.$store.state.player.elapsed * this.$store.state.player.total)
15
+ );
16
+ }
17
+ return '--:--';
18
+ },
19
+ totalTime(): string {
20
+ if (this.$store.state.player.elapsed && this.$store.state.player.elapsed > 0 && this.$store.state.player.total && this.$store.state.player.total > 0)
21
+ return DurationHelper.formatDuration(Math.round(this.$store.state.player.total));
22
+ return '--:--';
23
+ },
24
+ isPlaying(): boolean {
25
+ return 'PLAYING' === this.$store.state.player.status;
26
+ },
27
+ isPaused(): boolean {
28
+ return 'PAUSED' === this.$store.state.player.status;
29
+ },
30
+ podcast(): undefined|Podcast{
31
+ return this.$store.state.player.podcast;
32
+ },
33
+ isImage(): boolean {
34
+ return (state.player.image as boolean);
35
+ },
36
+ podcastImage(): string{
37
+ if (this.$store.state.player.podcast) return this.$store.state.player.podcast.imageUrl;
38
+ return '';
39
+ },
40
+ podcastShareUrl(): RouteLocationRaw|string {
41
+ if (this.podcast) {
42
+ return {
43
+ name: 'podcast',
44
+ params: { podcastId: this.podcast.podcastId.toString() },
45
+ query: { productor: this.$store.state.filter.organisationId },
46
+ };
47
+ }
48
+ return '';
49
+ },
50
+ isEmissionName(): boolean {
51
+ return (state.player.emissionName as boolean);
52
+ },
53
+ podcastTitle(): string {
54
+ if (this.$store.state.player.podcast) {
55
+ if (this.isEmissionName)
56
+ return this.emissionName + ' - ' + this.$store.state.player.podcast.title;
57
+ return this.$store.state.player.podcast.title;
58
+ }
59
+ if (this.$store.state.player.media) return this.$store.state.player.media.title;
60
+ if (this.$store.state.player.live) {
61
+ if (!this.hlsReady)
62
+ return this.$store.state.player.live.title + ' (' + this.$t('Start in a while') + ')';
63
+ return this.$store.state.player.live.title;
64
+ }
65
+ return '';
66
+ },
67
+ emissionName(): string {
68
+ if (this.$store.state.player.podcast) return this.$store.state.player.podcast.emission.name;
69
+ return '';
70
+ },
71
+ },
72
+ created(){
73
+ window.addEventListener('keydown', this.addKeyboardControl);
74
+ },
75
+ beforeUnmount() {
76
+ window.removeEventListener('keydown', this.addKeyboardControl);
77
+ },
78
+
79
+ methods: {
80
+ addKeyboardControl(event: KeyboardEvent): void{
81
+ if(!event || null ===event){return;}
82
+ const element = event.target as HTMLElement;
83
+ if (!element || 'INPUT' == element.tagName.toUpperCase() || 'TEXTAREA' == element.tagName.toUpperCase()){return;}
84
+ if (' ' === event.key || 'Spacebar' === event.key) {
85
+ event.preventDefault();
86
+ this.switchPausePlay();
87
+ }else if ('ArrowRight' === event.key && event.ctrlKey) {
88
+ const audioPlayer: HTMLAudioElement|null = document.querySelector('#audio-player');
89
+ if(!audioPlayer){return;}
90
+ audioPlayer.currentTime += 15;
91
+ }else if ('ArrowLeft' === event.key && event.ctrlKey) {
92
+ const audioPlayer: HTMLAudioElement|null = document.querySelector('#audio-player');
93
+ if(!audioPlayer){return;}
94
+ audioPlayer.currentTime -=15;
95
+ }
96
+ },
97
+ switchPausePlay(): void {
98
+ const audioPlayer: HTMLAudioElement|null = document.querySelector('#audio-player');
99
+ if(!audioPlayer){return;}
100
+ if (audioPlayer.paused) {
101
+ this.onPlay();
102
+ } else {
103
+ this.onPause();
104
+ }
105
+ },
106
+ onPlay(): void {
107
+ this.$store.commit('playerPause', false);
108
+ },
109
+ onPause(): void {
110
+ this.$store.commit('playerPause', true);
111
+ },
112
+ }
113
+ });
@@ -0,0 +1,113 @@
1
+ import { mapState } from 'vuex';
2
+ import { state } from '../../../store/paramStore';
3
+ import octopusApi from '@saooti/octopus-api';
4
+ /* eslint-disable */
5
+ let Hls:any = null;
6
+ /* eslint-enable */
7
+ import { StoreState } from '@/store/typeAppStore';
8
+ import { defineComponent } from 'vue';
9
+ export const playerLive = defineComponent({
10
+ data() {
11
+ return {
12
+ listenTime: 0 as number,
13
+ notListenTime: 0 as number,
14
+ lastSend: 0 as number,
15
+ hlsReady: false as boolean,
16
+ downloadId: null as string|null,
17
+ };
18
+ },
19
+ computed: {
20
+ ...mapState({
21
+ live(state: StoreState) { return state.player.live}
22
+ }),
23
+ },
24
+ methods: {
25
+ onPlay(): void {
26
+ this.$store.commit('playerPause', false);
27
+ },
28
+ async playLive(): Promise<void> {
29
+ if (!this.live) return;
30
+ const hlsStreamUrl =
31
+ state.podcastPage.hlsUri +
32
+ 'stream/dev.' +
33
+ this.live.conferenceId +
34
+ '/index.m3u8';
35
+ try {
36
+ await this.initHls(hlsStreamUrl);
37
+ } catch (error) {
38
+ console.log(error);
39
+ setTimeout(() => {
40
+ this.playLive();
41
+ }, 1000);
42
+ }
43
+ },
44
+ async initHls(hlsStreamUrl: string): Promise<void> {
45
+ return new Promise<void>(async(resolve, reject) => {
46
+ if(null === Hls){
47
+ //TODO -> Version light min quand ce sera possible
48
+ await import('hls.js/dist/hls.js').then((hlsLibrary) => {
49
+ Hls = hlsLibrary.default;
50
+ })
51
+ await import('hls.js').then((hlsLibrary) => {
52
+ Hls = hlsLibrary.default;
53
+ })
54
+ }
55
+ if (!Hls.isSupported()) {
56
+ reject('Hls is not supported ! ');
57
+ }
58
+ let hls = new Hls();
59
+ if(this.$store.state.authentication.isAuthenticated && this.$store.state.oAuthParam.accessToken){
60
+ hls = new Hls({xhrSetup:
61
+ (xhr: any) => {
62
+ xhr.setRequestHeader("Authorization", "Bearer " + this.$store.state.oAuthParam.accessToken);
63
+ }
64
+ }
65
+ );
66
+ }
67
+ hls.on(Hls.Events.MANIFEST_PARSED, async () => {
68
+ if(!this.live){ return; }
69
+ let downloadId = null;
70
+ try {
71
+ downloadId = await octopusApi.requestLiveDownloadId(
72
+ this.live.livePodcastId
73
+ );
74
+ await octopusApi.markPlayingLive(
75
+ this.live.livePodcastId,
76
+ downloadId,
77
+ 'octopus',
78
+ this.$store.state.authentication.organisationId
79
+ );
80
+ this.setDownloadId(downloadId);
81
+ } catch (error) {
82
+ console.log('ERROR downloadId');
83
+ }
84
+ this.hlsReady = true;
85
+ const audio: HTMLElement|null = document.getElementById('audio-player');
86
+ hls.attachMedia((audio as HTMLAudioElement));
87
+ await (audio as HTMLAudioElement).play();
88
+ this.onPlay();
89
+ resolve();
90
+ });
91
+ hls.on(Hls.Events.ERROR, async() => {
92
+ reject('There is an error while reading media content');
93
+ });
94
+ hls.loadSource(hlsStreamUrl);
95
+ });
96
+ },
97
+ setDownloadId(newValue: string|null): void {
98
+ this.endListeningProgress();
99
+ this.downloadId = newValue;
100
+ },
101
+ async endListeningProgress(): Promise<void> {
102
+ if (!this.downloadId) return;
103
+ await octopusApi.updatePlayerTime(
104
+ this.downloadId,
105
+ Math.round(this.listenTime)
106
+ );
107
+ this.setDownloadId(null);
108
+ this.notListenTime = 0;
109
+ this.lastSend = 0;
110
+ this.listenTime = 0;
111
+ },
112
+ },
113
+ })
@@ -0,0 +1,234 @@
1
+ import { mapState } from 'vuex';
2
+ import octopusApi from '@saooti/octopus-api';
3
+ import { CommentPodcast } from '@/store/class/general/comment';
4
+ import { cookies } from '../functions';
5
+ import { playerLive } from './playerLive';
6
+ import { playerComment } from './playerComment';
7
+ import { StoreState } from '@/store/typeAppStore';
8
+ import { defineComponent } from 'vue';
9
+ export const playerLogic = defineComponent({
10
+ mixins:[cookies,playerLive,playerComment],
11
+ data() {
12
+ return {
13
+ forceHide: false as boolean,
14
+ listenTime: 0 as number,
15
+ notListenTime: 0 as number,
16
+ lastSend: 0 as number,
17
+ downloadId: null as string|null,
18
+ playerError: false as boolean,
19
+ listenError: false as boolean,
20
+ percentLiveProgress: 0 as number,
21
+ durationLivePosition: 0 as number,
22
+ displayAlertBar: false as boolean,
23
+ hlsReady: false as boolean,
24
+ comments: [] as Array<CommentPodcast>,
25
+ showTimeline: false as boolean,
26
+ };
27
+ },
28
+ computed: {
29
+ ...mapState({
30
+ podcast (state: StoreState){ return state.player.podcast},
31
+ media: (state: StoreState) => state.player.media,
32
+ live: (state: StoreState) => state.player.live,
33
+ volume: (state: StoreState) => state.player.volume,
34
+ commentsLoaded: (state: StoreState) => state.comments.loadedComments,
35
+ percentProgress: (state: StoreState) => {
36
+ if(!state.player.elapsed){return 0;}
37
+ return state.player.elapsed * 100;
38
+ },
39
+ playerSeekTime: (state: StoreState) => state.player.seekTime,
40
+ }),
41
+ audioUrl(): string {
42
+ return this.getAudioUrl();
43
+ },
44
+ },
45
+
46
+ watch: {
47
+ audioUrl(): void{
48
+ this.playerError = false;
49
+ },
50
+ podcast: {
51
+ deep: true,
52
+ handler(){
53
+ this.reInitPlayer();
54
+ }
55
+ },
56
+ live: {
57
+ deep: true,
58
+ async handler(){
59
+ this.hlsReady = false;
60
+ this.reInitPlayer();
61
+ await this.playLive();
62
+ }
63
+ },
64
+ async listenTime(newVal): Promise<void> {
65
+ if ((!this.podcast && !this.live)||(!this.downloadId)||(newVal - this.lastSend < 10)) {
66
+ return;
67
+ }
68
+ this.lastSend = newVal;
69
+ await octopusApi.updatePlayerTime(
70
+ this.downloadId,
71
+ Math.round(newVal)
72
+ );
73
+ },
74
+ playerSeekTime(){
75
+ if(!this.playerSeekTime){return;}
76
+ if (this.$store.state.player.podcast || this.$store.state.player.live) {
77
+ this.notListenTime = this.playerSeekTime - this.listenTime;
78
+ }
79
+ const audioPlayer: HTMLAudioElement | null = document.querySelector('#audio-player');
80
+ if (!audioPlayer) return;
81
+ audioPlayer.currentTime = this.playerSeekTime;
82
+ },
83
+ },
84
+
85
+ mounted() {
86
+ window.addEventListener('beforeunload', this.endListeningProgress);
87
+ this.watchPlayerStatus();
88
+ },
89
+
90
+ methods: {
91
+ getAudioUrl(): string{
92
+ if (this.media) return this.media.audioUrl? this.media.audioUrl:"";
93
+ if (!this.podcast) return '';
94
+ if (!this.podcast.availability.visibility)
95
+ return this.podcast.audioStorageUrl;
96
+ if (this.listenError) return this.podcast.audioStorageUrl;
97
+ const parameters = [];
98
+ parameters.push('origin=octopus');
99
+ parameters.push('cookieName=player_' + this.podcast.podcastId);
100
+ parameters.push('listenerId='+this.getListenerId());
101
+ if (
102
+ this.$store.state.authentication &&
103
+ this.$store.state.authentication.organisationId
104
+ ) {
105
+ parameters.push(
106
+ 'distributorId=' + this.$store.state.authentication.organisationId
107
+ );
108
+ }
109
+ if("SECURED" === this.podcast.organisation.privacy && this.$store.state.authentication.isAuthenticated && this.$store.state.oAuthParam.accessToken){
110
+ parameters.push('access_token='+this.$store.state.oAuthParam.accessToken);
111
+ }
112
+ return this.podcast.audioUrl + '?' + parameters.join('&');
113
+ },
114
+ reInitPlayer():void{
115
+ this.setDownloadId(null);
116
+ this.listenError = false;
117
+ this.initComments();
118
+ },
119
+ stopPlayer(): void {
120
+ this.$store.commit('playerPlayPodcast');
121
+ },
122
+ getListenerId(): string{
123
+ let listenerId = this.getCookie("octopus_listenerId");
124
+ if(!listenerId){
125
+ listenerId = new Date().valueOf().toString() + Math.random();
126
+ let domain = "";
127
+ const domainArray: RegExpExecArray | null = /\.(.+)/.exec(window.location.host);
128
+ if(domainArray && null !== domainArray){
129
+ domain = domainArray[1];
130
+ }
131
+ this.setCookie("octopus_listenerId", listenerId, ';domain='+domain);
132
+ }
133
+ return listenerId;
134
+ },
135
+ watchPlayerStatus(): void {
136
+ this.$store.watch(
137
+ (state: StoreState) => state.player.status,
138
+ (newValue: string) => {
139
+ const audioPlayer: HTMLAudioElement | null = document.querySelector('#audio-player');
140
+ if (!audioPlayer) return;
141
+ if (this.live && !this.hlsReady) {
142
+ audioPlayer.pause();
143
+ this.percentLiveProgress = 0;
144
+ this.durationLivePosition = 0;
145
+ return;
146
+ }
147
+ if ('PAUSED' === newValue) {
148
+ audioPlayer.pause();
149
+ }else if ('PLAYING' === newValue){
150
+ audioPlayer.play();
151
+ }
152
+ }
153
+ );
154
+ },
155
+ onError(): void {
156
+ if (this.podcast && !this.listenError) {
157
+ this.listenError = true;
158
+ } else if (this.podcast || this.media) {
159
+ this.playerError = true;
160
+ }
161
+ },
162
+ onTimeUpdate(event: Event): void {
163
+ const mediaTarget = (event.currentTarget as HTMLMediaElement);
164
+ if (this.podcast || this.live) {
165
+ if (!this.downloadId) {
166
+ this.loadDownloadId();
167
+ }
168
+ if (
169
+ this.live &&
170
+ 0 === this.listenTime &&
171
+ 0 !== mediaTarget.currentTime
172
+ ) {
173
+ this.notListenTime = mediaTarget.currentTime;
174
+ this.listenTime = 1;
175
+ } else {
176
+ this.listenTime =
177
+ mediaTarget.currentTime - this.notListenTime;
178
+ }
179
+ }
180
+ const streamDuration = mediaTarget.duration;
181
+ if (!streamDuration) return;
182
+ if (!mediaTarget.currentTime) return;
183
+ if (!this.live) {
184
+ this.displayAlertBar = false;
185
+ this.percentLiveProgress = 100;
186
+ this.$store.commit('playerTotalTime', streamDuration);
187
+ this.$store.commit('playerElapsed', mediaTarget.currentTime / streamDuration);
188
+ return;
189
+ }
190
+ const scheduledDuration = this.live.duration / 1000;
191
+ if (scheduledDuration > streamDuration) {
192
+ this.displayAlertBar = false;
193
+ this.percentLiveProgress = (streamDuration / scheduledDuration) * 100;
194
+ this.$store.commit('playerTotalTime', scheduledDuration);
195
+ this.$store.commit(
196
+ 'playerElapsed',
197
+ mediaTarget.currentTime / scheduledDuration
198
+ );
199
+ } else {
200
+ this.percentLiveProgress = 100;
201
+ this.displayAlertBar = true;
202
+ this.durationLivePosition = (scheduledDuration / streamDuration) * 100;
203
+ this.$store.commit('playerTotalTime', streamDuration);
204
+ this.$store.commit('playerElapsed', mediaTarget.currentTime / streamDuration);
205
+ }
206
+ },
207
+ onFinished(): void {
208
+ this.setDownloadId(null);
209
+ if (this.live) {
210
+ const audio: HTMLElement|null = document.getElementById('audio-player');
211
+ if(audio){
212
+ (audio as HTMLAudioElement).src = '';
213
+ }
214
+ }
215
+ this.forceHide = true;
216
+ },
217
+ loadDownloadId(): void {
218
+ if (!this.podcast) return;
219
+ const matching_cookies = document.cookie
220
+ .split(';')
221
+ .map(item => {
222
+ const _return = item.trim().split('=');
223
+ return _return.map(item => item.trim());
224
+ })
225
+ .filter(item => {
226
+ if(!this.podcast){return '';}
227
+ return 'player_' + this.podcast.podcastId === item[0];
228
+ });
229
+ if (1 === matching_cookies.length) {
230
+ this.setDownloadId(matching_cookies[0][1]);
231
+ }
232
+ },
233
+ },
234
+ })
package/src/locale/de.ts CHANGED
@@ -297,4 +297,6 @@ export default{
297
297
  'From RSS': "Aus RSS-Feed",
298
298
  "User menu":"Benutzermenü",
299
299
  'Podcast tags': "Podcast-Tags",
300
+ "Enlarge":"Vergrößern",
301
+ "Reduce":"Reduzieren",
300
302
  }
package/src/locale/en.ts CHANGED
@@ -298,4 +298,6 @@ export default{
298
298
  "User menu":"User menu",
299
299
  'Podcast tags': 'Podcast tags',
300
300
  "You do not have the right to access this page":"You do not have the right to access this page",
301
+ "Enlarge":"Enlarge",
302
+ "Reduce":"Reduce",
301
303
  };
package/src/locale/es.ts CHANGED
@@ -297,4 +297,6 @@ export default{
297
297
  'From RSS': "Desde un canal RSS",
298
298
  "User menu":"Menú de usuario",
299
299
  'Podcast tags': 'Etiquetas de pódcast',
300
+ "Enlarge":"Agrandar",
301
+ "Reduce":"Reducir",
300
302
  }
package/src/locale/fr.ts CHANGED
@@ -298,4 +298,6 @@ export default{
298
298
  "User menu":"Menu utilisateur",
299
299
  'Podcast tags': "Mot-clé de l'épisode",
300
300
  "You do not have the right to access this page":"Vous n’avez pas le droit d’accéder à cette page",
301
+ "Enlarge":"Agrandir",
302
+ "Reduce":"Réduire",
301
303
  };
package/src/locale/it.ts CHANGED
@@ -295,4 +295,6 @@ export default{
295
295
  'Podcast tags': 'Tag podcast',
296
296
  "Term of use":"Termini d'uso",
297
297
  'More episodes of this category : ': "Altri episodi su questo tema : {name}",
298
+ "Enlarge":"Ingrandire",
299
+ "Reduce":"Ridurre",
298
300
  };
package/src/locale/sl.ts CHANGED
@@ -297,4 +297,6 @@ export default{
297
297
  'From RSS': "Z vira RSS",
298
298
  "User menu":"Uporabniški meni",
299
299
  'Podcast tags': 'Oznake podkastov',
300
+ "Enlarge":"Povečaj",
301
+ "Reduce":"Zmanjšaj",
300
302
  }
@@ -73,8 +73,6 @@ const state:paramStore = {
73
73
  player: {
74
74
  image: true,
75
75
  emissionName: false,
76
- clock: false,
77
- barTop: false,
78
76
  },
79
77
  footer: {
80
78
  contactLink: undefined,
@@ -164,9 +162,7 @@ export interface SearchPage{
164
162
  }
165
163
  export interface Player{
166
164
  image?: boolean
167
- emissionName?: boolean
168
- clock?: boolean
169
- barTop?: boolean
165
+ emissionName?: boolean
170
166
  }
171
167
  export interface Footer{
172
168
  contactLink?: string|undefined