diff --git a/client/composables/videoplayer/videoState.ts b/client/composables/videoplayer/videoState.ts index 1464b340e..88727f7de 100644 --- a/client/composables/videoplayer/videoState.ts +++ b/client/composables/videoplayer/videoState.ts @@ -68,14 +68,6 @@ export const useVideoState = ( adapterInstance.value.onPlaybackTimeUpdated(() => { updateTimeAndDuration(); }); - adapterInstance.value.onStreamActivated(() => { - updateTimeAndDuration(); - updateQualityLists(); - adapterInstance.value.setVolume(volumeStorage.value); - }); - adapterInstance.value.onStreamTeardownComplete(() => { - updateTimeAndDuration(); - }); adapterInstance.value.onBufferLevelUpdated(() => { videoState.bufferLevel = adapterInstance.value?.getBufferLevel() ?? 0; }); @@ -84,6 +76,9 @@ export const useVideoState = ( }); adapterInstance.value.onCanPlay(() => { videoState.buffering = false; + updateTimeAndDuration(); + updateQualityLists(); + adapterInstance.value.setVolume(volumeStorage.value); }); adapterInstance.value.onVolumeChanged(() => { videoState.volume = adapterInstance.value?.getVolume() ?? 1; diff --git a/client/utils/videoplayer/adapters/adapter.ts b/client/utils/videoplayer/adapters/adapter.ts index 39256a2aa..c08bde1ca 100644 --- a/client/utils/videoplayer/adapters/adapter.ts +++ b/client/utils/videoplayer/adapters/adapter.ts @@ -18,9 +18,6 @@ export interface VideoplaybackAdapterResponse { onPlaybackStarted: (callback: EventListenerCallback) => void; onPlaybackPaused: (callback: EventListenerCallback) => void; onPlaybackTimeUpdated: (callback: EventListenerCallback) => void; - onStreamActivated: (callback: EventListenerCallback) => void; - onStreamDeactivated: (callback: EventListenerCallback) => void; - onStreamTeardownComplete: (callback: EventListenerCallback) => void; onTextTracksAdded: (callback: EventListenerCallback) => void; onBufferLevelUpdated: (callback: EventListenerCallback) => void; onCanPlay: (callback: EventListenerCallback) => void; diff --git a/client/utils/videoplayer/adapters/shakaAdapter.ts b/client/utils/videoplayer/adapters/shakaAdapter.ts index 39d635ad1..46d09c47e 100644 --- a/client/utils/videoplayer/adapters/shakaAdapter.ts +++ b/client/utils/videoplayer/adapters/shakaAdapter.ts @@ -1,4 +1,3 @@ -import type { MediaInfo } from 'dashjs'; import type { EventListenerCallback, VideoplaybackAdapter } from './adapter'; export const shakaAdapter: VideoplaybackAdapter = async options => { @@ -21,6 +20,19 @@ export const shakaAdapter: VideoplaybackAdapter = async options => { shakaPlayer.addEventListener(event, callback); }; + const registerMultipleCallbacks = (events: string[]) => (callback: EventListenerCallback) => { + events.forEach(event => { + eventStorage.set(event, callback); + shakaPlayer.addEventListener(event, callback); + }); + }; + + const registerNativeCallback = + (event: keyof HTMLVideoElementEventMap) => (callback: EventListenerCallback) => { + eventStorage.set(event, callback); + videoRef.value.addEventListener(event, callback); + }; + const unregisterCallback = (event: string) => { const callback = eventStorage.get(event); if (callback) { @@ -28,6 +40,22 @@ export const shakaAdapter: VideoplaybackAdapter = async options => { } }; + const unregisterMultipleCallbacks = (events: string[]) => { + events.forEach(event => { + const callback = eventStorage.get(event); + if (callback) { + shakaPlayer.removeEventListener(event, callback); + } + }); + } + + const unregisterNativeCallback = (event: string) => { + const callback = eventStorage.get(event); + if (callback) { + videoRef.value.removeEventListener(event, callback); + } + }; + const onError = registerCallback('error'); const onMessage = registerCallback('message'); const onOpen = registerCallback('open'); @@ -45,52 +73,61 @@ export const shakaAdapter: VideoplaybackAdapter = async options => { }); // Register callbacks - const onPlaybackStarted = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_STARTED'); - const onPlaybackPaused = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_PAUSED'); - const onPlaybackTimeUpdated = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_TIME_UPDATED'); - const onStreamActivated = registerCallback('dashjs.MediaPlayer.events.STREAM_ACTIVATED'); - const onStreamDeactivated = registerCallback('dashjs.MediaPlayer.events.STREAM_DEACTIVATED'); - const onStreamTeardownComplete = registerCallback( - 'dashjs.MediaPlayer.events.STREAM_TEARDOWN_COMPLETE' - ); - const onTextTracksAdded = registerCallback('dashjs.MediaPlayer.events.TEXT_TRACKS_ADDED'); - const onBufferLevelUpdated = registerCallback('dashjs.MediaPlayer.events.BUFFER_LEVEL_UPDATED'); - const onCanPlay = registerCallback('dashjs.MediaPlayer.events.CAN_PLAY'); - const onWaiting = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_WAITING'); - const onVolumeChanged = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_VOLUME_CHANGED'); - const onPlaybackRateChanged = registerCallback('dashjs.MediaPlayer.events.PLAYBACK_RATE_CHANGED'); + const onPlaybackStarted = registerNativeCallback('playing'); + const onPlaybackPaused = registerNativeCallback('pause'); + const onPlaybackTimeUpdated = registerNativeCallback('timeupdate'); + const onTextTracksAdded = registerCallback('textchanged'); + const onBufferLevelUpdated = registerMultipleCallbacks(['segmentappended', 'onstatechange']); + const onCanPlay = registerNativeCallback('canplay'); + // https://nightly-dot-shaka-player-demo.appspot.com/docs/api/shaka.Player.html#.event:BufferingEvent + const onWaiting = registerCallback('buffering'); + const onVolumeChanged = registerNativeCallback('volumechange'); + const onPlaybackRateChanged = registerCallback('ratechange'); + const onQualityChanged = registerCallback('mediaqualitychanged'); + + const onVideoQualityChanged = (callback: EventListenerCallback) => { + onQualityChanged(e => { + console.log(e); + if (e.mediaType === 'video') { + callback(e.newQuality); + } + }); + }; + + const onAudioQualityChanged = (callback: EventListenerCallback) => { + onQualityChanged(e => { + console.log(e); + + if (e.mediaType === 'audio') { + callback(e); + } + }); + }; await shakaPlayer.attach(videoRef.value); const destroy = () => { - // unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_STARTED); - // unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_PAUSED); - // unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_TIME_UPDATED); - // unregisterCallback(dashjs.MediaPlayer.events.STREAM_ACTIVATED); - // unregisterCallback(dashjs.MediaPlayer.events.STREAM_DEACTIVATED); - // unregisterCallback(dashjs.MediaPlayer.events.STREAM_TEARDOWN_COMPLETE); - // unregisterCallback(dashjs.MediaPlayer.events.TEXT_TRACKS_ADDED); - // unregisterCallback(dashjs.MediaPlayer.events.BUFFER_LEVEL_UPDATED); - // unregisterCallback(dashjs.MediaPlayer.events.CAN_PLAY); - // unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_WAITING); - // unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_VOLUME_CHANGED); - // unregisterCallback(dashjs.MediaPlayer.events.PLAYBACK_RATE_CHANGED); + unregisterNativeCallback('playing'); + unregisterNativeCallback('pause'); + unregisterNativeCallback('timeupdate'); + unregisterCallback('textchanged'); + unregisterMultipleCallbacks(['segmentappended', 'onstatechange']); + unregisterNativeCallback('canplay'); + unregisterCallback('buffering'); + unregisterNativeCallback('volumechange'); + unregisterCallback('ratechange'); + unregisterCallback('mediaqualitychanged'); shakaPlayer.destroy(); }; // Getters const getBufferLevel = () => { - const bufferLevel = 0; - // if (typeof mediaPlayer.getDashMetrics === 'function') { - // const dashMetrics = mediaPlayer.getDashMetrics(); - // if (dashMetrics) { - // bufferLevel = dashMetrics.getCurrentBufferLevel('video'); - // if (!bufferLevel) { - // bufferLevel = dashMetrics.getCurrentBufferLevel('audio'); - // } - // } - // } + let bufferLevel = 0; + const bufferedInfo = shakaPlayer.getBufferedInfo(); + if (bufferedInfo) { + bufferLevel = bufferedInfo.total.sort((a, b) => a.end - b.end).reverse()[0].end; + } return bufferLevel; }; const getVideoQualityList = () => { @@ -160,15 +197,14 @@ export const shakaAdapter: VideoplaybackAdapter = async options => { onPlaybackStarted, onPlaybackPaused, onPlaybackTimeUpdated, - onStreamActivated, - onStreamDeactivated, - onStreamTeardownComplete, onTextTracksAdded, onBufferLevelUpdated, onPlaybackRateChanged, onCanPlay, onWaiting, onVolumeChanged, + onVideoQualityChanged, + onAudioQualityChanged, getTime, getDuration, diff --git a/server/src/core/videos/videos.service.ts b/server/src/core/videos/videos.service.ts index 1a2fbd57f..4ac57b480 100644 --- a/server/src/core/videos/videos.service.ts +++ b/server/src/core/videos/videos.service.ts @@ -61,8 +61,6 @@ export class VideosService { const client = await innertubeClient(); const videoInfo = await client.getInfo(id); - fs.writeFileSync(`/home/maurice/src/viewtube/${id}.json`, JSON.stringify(videoInfo, null, 2)); - const dashManifest = await videoInfo.toDash((url: URL) => { url.searchParams.append('__host', url.host); return url;