From b37a863c0afd8ad4c933d7487fea9ca06cea0263 Mon Sep 17 00:00:00 2001 From: mfcar Date: Sat, 4 May 2024 11:00:30 +0100 Subject: [PATCH 1/9] Initial transcription support --- .../components/app/MediaPlayerContainer.vue | 21 +++++- client/components/player/PlayerUi.vue | 12 ++- .../components/player/TranscriptionLine.vue | 29 +++++++ client/components/player/TranscriptionUi.vue | 40 ++++++++++ client/players/AudioTrack.js | 67 ++++++++++------- client/players/LocalAudioPlayer.js | 31 +++++++- client/strings/en-us.json | 3 +- server/controllers/LibraryItemController.js | 75 ++++++++++++------- server/objects/files/AudioTrack.js | 5 +- server/routers/ApiRouter.js | 7 +- 10 files changed, 227 insertions(+), 63 deletions(-) create mode 100644 client/components/player/TranscriptionLine.vue create mode 100644 client/components/player/TranscriptionUi.vue diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index 3c4b1d35b..c34e8595b 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -1,5 +1,6 @@ @@ -29,6 +30,9 @@ export default { const trackElement = document.getElementById("transcription-track"); this.cues = trackElement.track.cues; }, + seek(time) { + this.$emit('seek', time) + }, }, }; From 282203a30aa16091c2fe15301182a01cb42ed0ef Mon Sep 17 00:00:00 2001 From: mfcar Date: Sat, 4 May 2024 12:52:04 +0100 Subject: [PATCH 4/9] Automatically scrolls to active cue when enable/disable the transcription panel --- client/components/player/TranscriptionLine.vue | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/client/components/player/TranscriptionLine.vue b/client/components/player/TranscriptionLine.vue index 9f5ac3ddd..219461056 100644 --- a/client/components/player/TranscriptionLine.vue +++ b/client/components/player/TranscriptionLine.vue @@ -16,18 +16,26 @@ export default { }, methods: { clickSeek() { - const time = this.cue.startTime; - this.$emit('seek', time); + const time = this.cue.startTime + this.$emit('seek', time) + }, + scrollIntoView() { + this.$el.scrollIntoView({behavior: 'smooth'}) + } + }, + mounted() { + if (this.isActive) { + this.scrollIntoView() } }, created() { - this.cue.onenter = () => (this.isActive = true); - this.cue.onexit = () => (this.isActive = false); + this.cue.onenter = () => (this.isActive = true) + this.cue.onexit = () => (this.isActive = false) }, watch: { isActive(newVal) { if (newVal) { - this.$el.scrollIntoView({behavior: 'smooth'}); + this.scrollIntoView() } } } From 68d4dac4a20308e0cc679f6fe8b9475d9680ae42 Mon Sep 17 00:00:00 2001 From: mfcar Date: Sat, 4 May 2024 14:21:40 +0100 Subject: [PATCH 5/9] Avoid error: "Cannot read properties of null (reading 'track')" --- client/components/app/MediaPlayerContainer.vue | 5 +++-- client/components/player/TranscriptionUi.vue | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index f384c7dbf..937d6e59b 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -101,9 +101,9 @@ export default { 'playerHandler.playerState': function (newVal) { // Refresh the transcription UI when the audio track is changed if (newVal === 'LOADED') { - this.showTranscriptionUi = false; + this.showTranscriptionUi = false this.$nextTick(() => { - this.showTranscriptionUi = true; + this.showTranscriptionUi = true }); } }, @@ -507,6 +507,7 @@ export default { this.$eventBus.$on('playback-time-update', this.playbackTimeUpdate) this.$eventBus.$on('play-item', this.playLibraryItem) this.$eventBus.$on('pause-item', this.pauseItem) + this.showTranscriptionUi = false }, beforeDestroy() { this.$eventBus.$off('cast-session-active', this.castSessionActive) diff --git a/client/components/player/TranscriptionUi.vue b/client/components/player/TranscriptionUi.vue index 11f013b3c..6ea3f9ab1 100644 --- a/client/components/player/TranscriptionUi.vue +++ b/client/components/player/TranscriptionUi.vue @@ -17,9 +17,15 @@ export default { components: { TranscriptionLine }, + watch: { + trackElement() { + this.setCues(); + } + }, data() { return { cues: [], + trackElement: null }; }, mounted() { @@ -27,12 +33,17 @@ export default { }, methods: { init() { - const trackElement = document.getElementById("transcription-track"); - this.cues = trackElement.track.cues; + this.trackElement = document.getElementById("transcription-track") + if (this.trackElement && this.trackElement.track) { + this.setCues() + } }, seek(time) { this.$emit('seek', time) }, + setCues() { + this.cues = this.trackElement.track.cues + } }, }; From 35f51f4e986eb478a8d649e17bfce97cde631fa8 Mon Sep 17 00:00:00 2001 From: mfcar Date: Sat, 4 May 2024 20:26:05 +0100 Subject: [PATCH 6/9] Fix formatting --- client/players/AudioTrack.js | 69 +++++++++++++++--------------- client/players/LocalAudioPlayer.js | 2 +- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/client/players/AudioTrack.js b/client/players/AudioTrack.js index 2146c3e09..96d6a8d98 100644 --- a/client/players/AudioTrack.js +++ b/client/players/AudioTrack.js @@ -1,43 +1,42 @@ export default class AudioTrack { - constructor(track, userToken) { - this.index = track.index || 0 - this.startOffset = track.startOffset || 0 // Total time of all previous tracks - this.duration = track.duration || 0 - this.title = track.title || '' - this.contentUrl = track.contentUrl || null - this.transcriptUrl = track.transcriptUrl || null - this.mimeType = track.mimeType - this.metadata = track.metadata || {} + constructor(track, userToken) { + this.index = track.index || 0 + this.startOffset = track.startOffset || 0 // Total time of all previous tracks + this.duration = track.duration || 0 + this.title = track.title || '' + this.contentUrl = track.contentUrl || null + this.mimeType = track.mimeType + this.metadata = track.metadata || {} - this.userToken = userToken + this.userToken = userToken + } + + get fullContentUrl() { + if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl + + if (process.env.NODE_ENV === 'development') { + return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}` + } + return `${window.location.origin}${this.contentUrl}?token=${this.userToken}` + } + + get relativeContentUrl() { + if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl + + if (process.env.NODE_ENV === 'development') { + return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}` } - get fullContentUrl() { - if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl + return this.contentUrl + `?token=${this.userToken}` + } - if (process.env.NODE_ENV === 'development') { - return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}` - } - return `${window.location.origin}${this.contentUrl}?token=${this.userToken}` + get relativeTranscriptionUrl() { + if (!this.transcriptUrl || this.transcriptUrl.startsWith('http')) return this.transcriptUrl + + if (process.env.NODE_ENV === 'development') { + return `${process.env.serverUrl}${this.transcriptUrl}?token=${this.userToken}` } - get relativeContentUrl() { - if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl - - if (process.env.NODE_ENV === 'development') { - return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}` - } - - return this.contentUrl + `?token=${this.userToken}` - } - - get relativeTranscriptionUrl() { - if (!this.transcriptUrl || this.transcriptUrl.startsWith('http')) return this.transcriptUrl - - if (process.env.NODE_ENV === 'development') { - return `${process.env.serverUrl}${this.transcriptUrl}?token=${this.userToken}` - } - - return this.transcriptUrl + `?token=${this.userToken}` - } + return this.transcriptUrl + `?token=${this.userToken}` + } } diff --git a/client/players/LocalAudioPlayer.js b/client/players/LocalAudioPlayer.js index 884951c93..f56f89b90 100644 --- a/client/players/LocalAudioPlayer.js +++ b/client/players/LocalAudioPlayer.js @@ -172,7 +172,7 @@ export default class LocalAudioPlayer extends EventEmitter { this.hlsInstance.attachMedia(this.player) this.hlsInstance.on(Hls.Events.MEDIA_ATTACHED, () => { - this.hlsInstance.loadSource(this.currentTrack.relativeContentUrl) + this.hlsInstance.loadSource(this.currentTrack.relativeContentUrl) this.hlsInstance.on(Hls.Events.MANIFEST_PARSED, () => { console.log('[HLS] Manifest Parsed') From bfcf4e317f40425c60c58b113f890b3df9e60a26 Mon Sep 17 00:00:00 2001 From: mfcar Date: Sat, 4 May 2024 20:31:39 +0100 Subject: [PATCH 7/9] Remove semicolon --- .../components/app/MediaPlayerContainer.vue | 2 +- client/components/player/TranscriptionUi.vue | 8 ++++---- client/players/LocalAudioPlayer.js | 20 +++++++++---------- server/controllers/LibraryItemController.js | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/client/components/app/MediaPlayerContainer.vue b/client/components/app/MediaPlayerContainer.vue index 937d6e59b..82ef1e8c2 100644 --- a/client/components/app/MediaPlayerContainer.vue +++ b/client/components/app/MediaPlayerContainer.vue @@ -71,7 +71,7 @@