# @eyevinn/media-event-filter 中文文档

规范地址：https://npmcn.com/package/%40eyevinn/media-event-filter/

版本：3\.4\.1
npm 元数据更新时间：2026-01-12T14:50:09.833Z
中文译文更新时间：2026-11-14T06:34:14.129Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40eyevinn/media-event-filter
原文对照：https://npmcn.com/package/%40eyevinn/media-event-filter/?lang=original
项目主页：https://github.com/Eyevinn/media-event-filter#readme
源码仓库：https://github.com/Eyevinn/media-event-filter

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：91.3 kB，43 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- 首次发布：2023-03-02T08:15:16.659Z
- 最新版本发布：2024-10-30T10:09:12.380Z
- 近 30 天下载量：5013（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：16（近 12 个月 0 个）

## 中文简介

HTML5 媒体事件过滤器

## 安装

```sh
npm install @eyevinn/media-event-filter
```

也可以使用：`pnpm add @eyevinn/media-event-filter`、`yarn add @eyevinn/media-event-filter`、`bun add @eyevinn/media-event-filter`

## README

# 媒体事件过滤器

用于从 a 对重播事件生成一个正常的默认解释的可依赖性自由而微小的套件 [HTML 介质](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement)。 。 。 .

## 为什么

HTML5 视频元素不产生符合跟踪器和用户界面要求的更新的一致事件集,比如 `loaded`, (中文(简体) ), `buffering` 或者说 `seeking`。 。 。 .

在"媒体源扩展"上方所搭建的不同玩家引擎都有自己的执行功能来收听事件.

这个过滤器旨在提供一个单一的真理源,可以跨玩家引擎和浏览器本土回放使用.

坚持 [Eyvinn 玩家分析规格](https://github.com/Eyevinn/player-analytics-specification)。 。 。 .

## 概览

```typescript
/** Loading of stream is complete, playback is ready to start */
/** It is now safe to let the user press a play button */
"loaded";
/** A seek has started */
"seeking";
/** A seek has ended  */
"seeked";
/** Buffering has started */
/** Does not trigger during seek, cancelled by a seek */
"buffering";
/** Buffering has ended */
/** Does not trigger during seek */
"buffered";
/** A request to start playing again has been made */
"play";
/** The stream has started playing after loading completed
 *  OR the stream has started playing after the stream was previously paused */
"playing";
/** The stream has been paused */
"pause";
/** The end of the stream was reached */
"ended";
/** A timeupdate event */
"timeupdate";
```

## 限制

不支持本地 HTML5 MSE 控件( N)`<video controls>`) (中文(简体) ). 它有效,但事件序列不会在所有浏览器中严格遵循EPAS.

## 使用量

`npm install @eyevinn/media-event-filter`

`yarn add @eyevinn/media-event-filter`

创建和监听事件过滤器的示例 .

```typescript
import {
  getMediaEventFilter,
  FilteredMediaEvent,
} from "@eyevinn/media-event-filter";

const videoElement = document.createElement("video");

// Using a switch statement

const mediaEventFilter = getMediaEventFilter({
  mediaElement: videoElement,
  callback: (event: FilteredMediaEvent) => {
    switch (event) {
      case FilteredMediaEvent.LOADED:
        // handle loaded
        break;
      case FilteredMediaEvent.BUFFERING:
        // handle buffering
        break;
      case FilteredMediaEvent.BUFFERED:
      // handle buffered
      // ...
      default:
        break;
    }
  },
});

// Call when done
mediaEventFilter.teardown();
```

```typescript
// Object notation can also be used

const handlers = {
  [FilteredMediaEvent.LOADED]: () => {
    /* handle loaded */
  },
  [FilteredMediaEvent.BUFFERING]: () => {
    /* handle buffering */
  },
  [FilteredMediaEvent.BUFFERED]: () => {
    /* handle buffered */
  },
  // ...
};

const mediaEventFilter = getMediaEventFilter({
  mediaElement: videoElement,
  callback: (event: FilteredMediaEvent) => handlers[event]?.(),
});
```

```typescript
// It is safe to use destructuring

const { teardown } = getMediaEventFilter({
  /* ... */
});

teardown();
```

### 样本 Shaka + 反应组件

滤波器可以方便地在Shaka上方建立反应UI.

裸骨样本集成(参见 [代码](https://codepen.io/atlimar/pen/wvEmpXM?editors=1010):

```javascript
import { useCallback, useEffect, useMemo, useRef, useState } from "React";
import shaka from "shaka-player";
import {
  FilteredMediaEvent,
  getMediaEventFilter,
} from "@eyevinn/media-event-filter";

const PlayerComponent = ({ videoUrl }) => {
  const videoRef = useRef(null);
  const [playing, setPlaying] = useState(false);
  const [loading, setLoading] = useState(true);
  const [blocked, setBlocked] = useState(false);

  useEffect(() => {
    if (!videoUrl || !videoRef.current) return () => {};

    const eventFilter = getMediaEventFilter({
      mediaElement: videoRef.current,
      // add your state handlers here
      callback: (event) => {
        switch (event) {
          case FilteredMediaEvent.LOADED:
            setLoading(false);

            // attempt autoplay
            videoRef.current.play().catch((e) => {
              // catch autoplay block
              if (e.name.indexOf("NotAllowedError") > -1) {
                setBlocked(true);
              }
            });
            break;
          case FilteredMediaEvent.PLAYING:
            // reset autplay blocked
            setBlocked(false);
            // we're playing!
            setPlaying(true);
            break;
          case FilteredMediaEvent.ENDED:
          case FilteredMediaEvent.PAUSE:
            setPlaying(false);
            break;
          default:
            break;
        }
      },
    });

    const player = new shaka.Player(videoRef.current);

    // Add configuration if needed
    // player.configure()

    player
      // start loading the stream
      .load(videoUrl)
      // catch errors during load
      .catch(console.error);

    // Kill player when unmounted
    return () => {
      player.destroy();
      eventFilter.teardown();
    };
  }, [videoUrl, videoRef]);

  const play = useCallback(() => {
    if (!videoRef.current) return;

    videoRef.current.play();
  }, [videoRef]);

  const pause = useCallback(() => {
    if (!videoRef.current) return;

    videoRef.current.pause();
  }, [videoRef]);

  return (
    <div style={{ width: "720px", margin: "20px auto" }}>
      {loading && <p>Video is Loading</p>}

      {!loading &&
        (playing ? (
          <button type="button" onClick={pause}>
            Pause
          </button>
        ) : (
          <button type="button" onClick={play}>
            Play
          </button>
        ))}

      {blocked && <p>Autoplay blocked, please start playback manually</p>}

      <video ref={videoRef} style={{ width: "100%", height: "auto" }} />
    </div>
  );
};
```

```javascript
// Use it:
<PlayerComponent videoUrl="https://bitmovin-a.akamaihd.net/content/MI201109210084_1/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd" />
```

## 福利

无论引擎(Shaka, Hls.js, DashJS, 原生)或浏览器(Chrome, Firefox, Safari),为回放事件获取单一的真相来源.

将事件直接插入您的 UI 状态管理中, 以获取重播状态更新的可靠真相源 .

事件序列映射直接通向受欢迎的跟踪提供者并回放SDK而不进行进一步过滤,比如Youbora,Comscore,Yosspace,或Nielsen. _如果你们也得到支持,我们欢迎公关更新这个名单!_

兼容 [电子考绩制度](https://github.com/Eyevinn/player-analytics-specification)。 。 。 .

## 活动

事件描述及其顺序.

### 示例顺序

```typescript
LOADED; // playback is ready to start
PLAYING; // playback started
SEEKING; // seek requested
PAUSED; // manual pause
PLAY; // manual play
SEEKED; // seek finished
PLAYING; // video is rolling again
BUFFERING; // unable to continue playing due to missing buffer
BUFFERED; // buffer ended by incoming seek request
SEEKING; // seek requested
SEEKED; // seek finished
PAUSED; // manual pause
PLAY; // manual play
PLAYING; // video is rolling again
ENDED; // video reached the end
```

### 已装入

视频的初始负载已经完成,准备开始播放.

装入前没有其它事件可以触发 .

### 请求

寻已起.

如果正在缓冲,则在寻求之前会被触发.

缓冲事件无法在搜索中触发 .

装入前不能触发 .

### 已寻求

寻觅已后.

装入前不能触发 .

没有先前的寻找事件就无法触发.

### 缓冲

缓起已起.

无法在搜索中触发 .

装入前不能触发 .

### 缓冲

缓冲已经结束,或因寻求而中断.

无法在搜索中触发 .

没有先前的缓冲事件就无法触发 .

### 播放

已请求播放 .

装入前不能触发 .

如果视频之前没有暂停, 则无法触发 .

### 播放

播放已经开始 .

装入前不能触发 .

寻找时不能触发 .

缓冲时不能触发 .

如果视频之前没有暂停, 则无法触发 .

求取或缓冲时请求的玩法会在求取或缓冲完成后触发玩法.

### 暂停

播放已暂停 .

寻求或缓冲并不算作穷困.

装入前不能触发 .

### 时间更新日期

时间更新事件

装入前不能触发 .

### 结束

玩家已到达一流的尽头.

允许在流尾到达后重新启动流 `allowResumeAfterEnded` 改为 `true`。 。 。 .

## 捐款

欢迎为改进不同引擎的兼容性或增加支持,跟踪解决方案,浏览器做出贡献.

### Git 工作方法

项目使用特色分支,a [重组合并策略](https://www.atlassian.com/git/tutorials/merging-vs-rebasing)。 。 。 .

确保你有 `git pull` 设置为再基准模式 :

`git config pull.rebase true`

可以选择添加 `--global` 标记为上方命令.

要开始研究一个新的功能: `git checkout <feature branch name>`。 。 。 .

由于该项目使用语义释放到 **自动生成释放注释** 基于承诺,在作出承诺时必须遵守一些规则.

这个项目使用 [常规承诺](https://www.conventionalcommits.org/en/v1.0.0/#summary)。 。 。 .

读取 [使用有纪律的 Git](https://drewdevault.com/2019/02/25/Using-git-with-discipline.html)。 。 。 .

读取 [如何撰写提交信件](https://chris.beams.io/posts/git-commit/)。 。 。 .

承诺应:

-   包含一个单一的更改集( 较小的承诺更好)
-   通过测试、打字和打字检查
-   无法被打破

它与能够节省时间的自动化同时,也能够通过 [双节](https://git-scm.com/docs/git-bisect)使捕虫成为几分钟而不是几天的事 外有多篇关于"分形"魔法的文章.

承诺信息的基本结构:

```
<type>[optional scope]: <title starting with verb in infinitive>

[optional body]

[optional footer]
```

自动放出注释要效果好,尝试描述被添加或被更改的内容,而不是描述代码的作用. 示例

`fix(seek): rewrite calculation in seek module` `// bad, the consumer does not know what issue this fixes`

`fix(seek): stop player from freezing after seek` `// good, the consumer understands what is now working again`

### 开发

要启动 Dev 服务器 : `pnpm dev`检查 `demo` 财务报告和审定财务报表 `public/index.html` 详细情况.

熟悉 HTML5 视频标准、 shaka、hlsjs 或其他引擎 建议在发言前先发言.

[https://www.w3.org/TR/2011/WD-html5-20110113/video.html 互联网档案馆的存檔,存档日期2013-12-21](https://www.w3.org/TR/2011/WD-html5-20110113/video.html)

[https://html.spec.whywg.org/multipage/media.html 互联网档案馆的存檔,存档日期2013-12-22](https://html.spec.whatwg.org/multipage/media.html)

[https://html.spec.whywg.org/multipage/media.html#mediaevents (中文(简体) )](https://html.spec.whatwg.org/multipage/media.html#mediaevents)

试验用 Shaka 2.5.X - 4.X.X

在Safari接受本地视频测试

用hls.js测试

在Safari 13.1+、Firefox、Chrome、Edge试验过

在OSX、Windows、Linux上测试

### 释放

释放是通过github动作被触发的,该动作将自动递增版本并基于承诺写入更动日志.

可以通过运行进行手动发布 `pnpm release`。 。 。 .

# 支助

加入我们 [slack 社区](http://slack.streamingtech.se/) 您可以在其中张贴任何关于我们开放源代码项目的问题。 Eyevin的咨询业务也可以提供:

-   本构成部分的进一步发展
-   此组件定制并整合到您的平台
-   支助和维持协定

联系人 [销售量@ eyevin.se](mailto:sales@eyevinn.se) 如果你有兴趣.

# 关于 Eyevinn 技术

[目光技术](https://www.eyevinntechnology.se/) 一家独立咨询公司,专门从事录像和流媒体制作。 独立的方式,我们不与任何平台或技术供应商进行商业联系。 作为我们创新和推动工业前进的途径,我们开发了概念证明和工具。 我们学到的东西和我们写的代码 与行业分享 [博客](https://dev.to/video) 并且通过公开提供我们写的代码.

想知道更多关于"Eyevin" 和如何工作在这里。 联系我们 [工作@ eyevin.se](mailto:work@eyevinn.se)来啊!

## 常见问题

### @eyevinn/media-event-filter 是什么？

HTML5 媒体事件过滤器

### 如何安装 @eyevinn/media-event-filter？

在项目目录运行 npm install @eyevinn/media-event-filter，或使用 pnpm add / yarn add / bun add。

### @eyevinn/media-event-filter 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @eyevinn/media-event-filter 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @eyevinn/media-event-filter 可以商用吗？

@eyevinn/media-event-filter 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @eyevinn/media-event-filter 的下载量有多少？

根据 npm 官方下载统计，@eyevinn/media-event-filter 在 2026/10/14 – 2026/11/12 这 30 天内被下载 5,013 次，日均约 167 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @eyevinn/media-event-filter 还在维护吗？

最新版本 3\.4\.1 发布于 2024/10/30（2 年前）；至今共发布 16 个版本，其中过去 12 个月发布了 0 个；首次发布于 2023/03/02。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

