videomail-client ✉
在联系表单中录制视频!
现在,您可以在几秒内将现代浏览器和移动设备上的任何网络摄像头录制内容编码为 MP4 + WebM。 无需 Flash、Java 或任何其他插件/附加组件。只需 TypeScript,编译为带有声明的 ESM。
实时演示
在 videomail-client.netlify.app 上尽情体验
实际应用场景
完整版及其所有功能可在 videomail.io 上找到。
此外还有更多:
还有更多。我们正在推进……
Storybook(示例)
要在本地浏览器中查看一些示例,只需运行以下两条命令:
npm installnpm run storybook
就是这样。简单得像苹果派。
选项
你可以向 VideomailClient 构造函数传递许多选项。请查看 src/options.ts 处的带注释源代码。
在大多数情况下,这些默认值已经足够。只有一个选项 whitelistKey 在你部署自己的站点时需要更改,参见 Whitelist。
查看 /src/stories 文件夹中的示例应该能给你一些如何使用这些选项的思路。
API
new VideomailClient()videomailClient.on()videomailClient.show()videomailClient.hide()videomailClient.record()videomailClient.replay()videomailClient.startOver()videomailClient.getByAlias()videomailClient.getByKey()videomailClient.unload()videomailClient.hide()videomailClient.isDirty()videomailClient.isRecording()videomailClient.isBuilt()videomailClient.submit()videomailClient.getLogLines()videomailClient.setLimitSeconds()
new VideomailClient([options])
构造函数接受一个包含可选 options 的 JSON。示例:
const videomailClient = new VideomailClient({ whitelistKey: "my whitelist key" });
videomailClient.on([event,] [callback])
VideomailClient 类继承自 EventEmitter,并为您的应用发出许多有用的事件。以下是一个示例:
videomailClient.on("FORM_READY", () => {
// form is ready for recording
});
videomailClient.on("SUBMITTED", ({ videomail, response }) => {
// continue with your own app logic in your javascript code if you want to process
// something else further after form submission.
});
支持的事件
在 src/types/events/index.ts 中查看。
它们应该是自解释的。如果不是,请要求提供更好的文档。然后,其中一些事件可能带有参数。
videomail 客户端已经内置了内部错误处理机制,因此无需添加代码来显示错误。但根据您应用程序的逻辑,您可能希望使用自己的错误监听器进一步处理错误。
顺便说一下,所有 videomail 错误都是 VideomailError 的实例,继承自原生 Error 类,并带有用于调试奇怪错误的附加属性。
videomailClient.show()
自动在 DOM 中填充一个用于视频录制的表单。默认情况下,ID 为 videomail 的 HTML 元素将被填充,详见选项。
videomailClient.record()
强制启动录音,无需按下录音按钮。适用于特殊场景。
videomailClient.replay(videomail[, parentElementId])
手动为指定的 videomail 在父元素内添加一个视频容器。请参阅 stories 以获取一些灵感。
如果 parentElement 是一个 ID(字符串),则它将在内部被解析为一个 DOM 元素。如果未提供父元素,则会在 containerId 内自动生成一个 replay 容器。
另外请注意,当父元素已经包含一个这样的视频容器时
<video class="replay"></video>
那么这将用于替代添加新的 dom 元素。
videomailClient.startOver()
重新开始,重置所有内容并返回就绪状态。如果您想在同一实例中提交另一封 videomail,此方法非常有用。
videomailClient.getByAlias(alias)
通过给定的别名异步查询 videomail(JSON),以便进行进一步的查询或处理。获取别名有两种方式:
- 表单提交到您自己的服务器时,在表单主体中的
videomail_alias下可以找到它。 - 从
submitted事件中获取别名,并在代码中进一步使用它。
videomailClient.unload()
手动卸载摄像头及所有其他内部事件监听器。
videomailClient.hide()
隐藏所有视觉元素(但不会卸载任何内容)。
videomailClient.isDirty()
当已录制视频且表单存在时返回 true。在关闭窗口前检查某些内容时非常有用,例如以下用例:显示一个窗口确认对话框,以确保用户没有忘记提交已录制的视频。
videomailClient.isRecording()
当视频正在录制时返回 true。
videomailClient.submit()
仅供高级使用:特别是当提交按钮被其他 HTML 层覆盖,且 videomail 客户端无法处理点击事件时。 调用此函数将手动触发已录制 videomail 的提交。但仅在其他所有条件均有效时才会执行。若无效,则不会发生任何操作。
videomailClient.getLogLines()
仅供高级用户使用:返回一组日志行,显示最近已覆盖的代码。如果您想要调试某些棘手的问题,这将非常有用。
videomailClient.setLimitSeconds()
仅供高级用户使用:设置以秒为单位的录音时长限制。如果您希望动态更改录音时长,此功能非常有用。
视频邮件服务器上存储了什么?
以下是一个示例 JSON,展示了存在哪些视频邮件元数据,这些数据会被存储在服务器上,并且您可以自行获取以供进一步使用。 它在 SUBMITTED 事件下的 videomail 对象中发出:
{
"subject": "some subject",
"from": "some@sender.com",
"body": "A text body",
"recordingStats": {
"avgFps": 15.151515151515152,
"wantedFps": 15,
"avgInterval": 62.09090909090909,
"wantedInterval": 66.66666666666667,
"intervalSum": 683,
"framesCount": 11,
"videoType": "webm",
"waitingTime": 192
},
"width": 320,
"height": 240,
"videomailClientVersion": "2.4.11",
"whitelistKey": "videomail-client-demo",
"alias": "some-subject-183622500964",
"dateCreated": 1541130589811,
"url": "https://videomail.io/videomail/some-subject-150322500964",
"key": "11e8-de52-55ac2630-b22b-71959562a989",
"expirationPretty": "1 hour",
"expiresAfter": 1541134189811,
"siteName": "Videomail Client Example",
"webm": "https://videomail.io/videomail/some-subject-183622500964/type/webm/",
"poster": "https://videomail.io/videomail/some-subject-183622500964/poster/",
"dateCreatedPretty": "Nov 2, 2018, 4:49 PM",
"expiresAfterPretty": "Nov 2, 2018, 5:49 PM",
"expiresAfterIso": "2018-11-02T04:49:49.811Z"
}
您也可以通过 videomailClient.getByKey() API 调用获取上述所有内容。
表单提交
默认情况下,videomail-client 会中断表单提交 e.preventDefault(),并首先将 videomail 本身提交到 videomail 服务器。videomail 服务器会回复有用的数据,例如 videomail 别名、其他元数据,然后才恢复实际的表单提交。
如果这在你这边似乎不起作用,这通常是因为表单和提交按钮无法找到,且提交事件触发得太晚。要修复此问题,你需要更正选项下的选择器。以下是与表单相关的重要选择器:
selectors: {
"formId": null,
"submitButtonId": null,
"submitButtonSelector": null
},
当这些值为 null(默认值)时,videomail-client 会尝试自动检测它们。但由于表单位于 DOM 的其他位置,或者提交按钮没有 type=submit 等属性,检测可能会失败。
在表单提交中包含 videomail 元数据
如果您希望在提交到自有服务器的表单中包含 videomail 元数据,请启用 submitWithVideomail 选项。
否则,表单主体中仅包含 videomail 别名,之后需要调用 videomail.getByAlias(alias) 来获取这些数据。
白名单
示例可立即在 https://localhost:8443 上运行。这是因为 localhost 已在远程 Videomail 服务器上加入白名单。https://localhost 和 https://localhost:443 也针对本地开发加入了白名单。其他 IP 地址将无法使用。如果这造成了问题,请联系我,我可以添加更多白名单。
换句话说,如果你的 Web 服务器通过 localhost 以外的域名连接,Videomail-Client 将被限制向负责存储和发送 videomail 的远程 Videomail 服务器发送媒体数据包。要解决此问题,只需在 https://videomail.io/whitelist 提交白名单申请。然后,您应该会获得一个新的白名单密钥以及供您自己使用的白名单 URL 列表。
向后兼容性
忘掉旧版 IE、11 版本以下的 Safari 以及老旧的 iPhone/iPad,因为它们不支持 getUserMedia()。不要怪我,要怪就怪 Apple + Microsoft chuckle - 目前,这些浏览器运行起来毫无问题:
- Firefox >= 34
- Google Chrome >= 32
- Microsoft Edge >= 12
- Internet Explorer >= 12
- Opera >= 26
- Chrome for Android >= 39
- Android Browser >= 37
- Safari >= 11
来源:http://caniuse.com/#search=getUserMedia
附注:在 Safari 和 iPhone/iPad 上,您可以毫无问题地播放视频邮件。再说一遍:在 Apple 采取行动之前,它们尚不具备录制功能。
插件
有一个 Videomail WordPress 插件,太棒了! https://wordpress.org/plugins/videomail-for-ninja-forms/
它是流行的表单构建器 Ninja Forms 的扩展。安装 videomail 插件后,你只需将实时摄像头输入拖放到表单中!并指定提交后应执行的操作。如此简单。
备注
更新日志
维护起来太难了。直接做 git log 或查看这里
https://github.com/binarykitchen/videomail-client/commits/master
噪音
这里有一些关于 Videomail 在现实世界中的噪音:
未完成的蜕变(又名开发)
这仅仅是个开始。我会在未来添加更多内容。
请多包涵,有很多问题需要攻克,尤其是性能、音频部分,以及一些单元测试缺失。除非证明其有效,否则我不想花太多时间在完美主义上,然后我会逐块重写。
致谢
这些人激励了我完成这个很棒的项目。非常感谢:
- Heath Sadler (设计师)
- Stefan Weber (设计师)
- Zack Best (律师)
- Sonia Pivac (设计师)
- Dominic Tarr (造船匠)
- Daniel Ly (开发者)
- Nicholas Buchanan (未知)
- Kelvin Wong (游戏玩家)
- Isaac Johnston (顾问)
他们都值得得到大量的回报。非常感谢。
代码质量
我承认,代码并不顶尖,需要大量重写。信不信由你,在过去四年里我已经重写了大约三次。这是一个很好的例子,说明软件很难做到完美。而且既然我在这里已经坦诚相告,我认为稳定性和 bug 修复应优先于完美主义,否则你会失去用户。现实如此。
最终理念
这个星球已经完全被卖掉了。而且言语被高估了。因此,我的首要目标不是将其变成商业产品,而是推广一种很酷但被低估的语言:手语。