监听 HTMLMediaElement 播放状态的 RxJS 观察器(观看记录上报核心逻辑)

189 阅读1分钟

监听 HTMLMediaElement 播放状态的 RxJS 观察器

这是一个用于监听 HTMLMediaElement 播放状态的自定义 RxJS 观察器。当满足以下条件时,会自动输出播放记录:

  1. 播放时间超过指定秒数。
  2. 用户触发了暂停、播放、快进、快退、停止、结束等操作会自动输出播放记录。

整体设计思路

  1. 使用 RxJS 的 Subject 监听 HTMLMediaElement 的事件。
  2. 使用一个 Subject 作为检测的标记,当用户操作或超时时触发检测。
  3. 使用 onTimeUpdate 事件监听播放时间的变化。

参数

  • element(HTMLMediaElement):需要监听的媒体元素。
  • seconds(Number):正常播放时间超过这个时间才会调用回调函数。

示例代码

import { 
    fromEvent,
    bufferWhen,
    merge,
    filter,
    map,
    Subject,
    switchMap,
    interval,
    takeUntil,
 } from 'rxjs';

/**
 * 订阅HTML媒体元素的事件并缓冲播放记录。
 * 
 * @param {HTMLMediaElement} element - 要监听的HTML媒体元素。
 * @param {number} seconds - 缓冲播放记录的间隔(秒)。
 * @returns {Observable} - 一个发出缓冲播放记录的Observable。
 */
function subscribeEventToHtmlMediaElement(element, seconds) {
    // 创建一个关于媒体元素用户操作的Observable
    const userActionMap$ = merge(
        ...['play', 'pause', 'seeking', 'seeked', 'ended'].map(
            action => fromEvent(element, action)
        )
    );
    
    // 创建一个在每次用户操作后间隔一段时间的Observable,直到下一次操作
    const intervalAfterEachUserActionSubject$ = userActionMap$.pipe(
        switchMap(() => {
            return interval(seconds * 1000).pipe(
                takeUntil(userActionMap$)
            );
        })
    );

    // 用于缓冲用户操作和间隔的主题
    const bufferWhenSubject$ = new Subject();
    merge(userActionMap$, intervalAfterEachUserActionSubject$).subscribe(bufferWhenSubject$);

    // 基于时间更新发出缓冲播放记录的Observable
    return fromEvent(element, 'timeupdate').pipe(
        map(() => element.currentTime),
        bufferWhen(() => bufferWhenSubject$),
        filter((timeList) => timeList.length > 0),
        map((timeList) => [timeList[0], timeList[timeList.length - 1]]),
    );
}


客户端使用

//  首先选中元素
const element = document.querySelector('.video');
//  每5秒记录一次播放时间
subscribeEventToHtmlMediaElement(element, 5).subscribe((timeList)=>{
  //  timeList形如[0, 5], 但是由于timeupdate事件的特性,很多时候都不是整数
  console.log(timeList);
});

下图是里面一个不容易理解的switchMap的图解,觉得挺好,就贴到这儿

switchMap-marble-diagram.jpg