1. Project Overview & Quickstart (DIYgod/DPlayer)
File: README.md
DPlayer
🍭 Wow, such a lovely HTML5 danmaku video player
Introduction
DPlayer is a lovely HTML5 danmaku video player to help people build video and danmaku easily.
DPlayer supports:
- Streaming formats
- HLS
- FLV
- MPEG DASH
- WebTorrent
- Any other custom streaming formats
- Media formats
- MP4 H.264
- WebM
- Ogg Theora Vorbis
- Features
- Danmaku
- Screenshot
- Hotkeys
- Quality switching
- Thumbnails
- Subtitle
Using DPlayer on your project? Let me know!
Thanks
Sponsors
Contributors
Related Projects
Feel free to submit yours in Let me know!
Tooling
- DPlayer-thumbnails: generate video thumbnails
Danmaku api
- DPlayer-node: Node.js
- laravel-danmaku: PHP
- dplayer-live-backend: Node.js, WebSocket live backend
- RailsGun: Ruby
Plugins
- DPlayer-for-typecho: Typecho
- Hexo-tag-dplayer: Hexo
- DPlayer_for_Z-BlogPHP: Z-BlogPHP
- DPlayer for Discuz!: Discuz!
- DPlayer for WordPress: WordPress
- DPlayerHandle: WordPress
- Selection: WordPress
- Vue-DPlayer: Vue
- react-dplayer: React
- rc-dplayer: React
Other
- DPlayer-Lite: lite version
- hlsjs-p2p-engine: Let your viewers become your unlimitedly scalable CDN
- CBPlayer: Dplayer with CDNBye P2P plugin built in, supporting HLS, MP4 and MPEG-DASH P2P streaming.
- Feel free to submit yours in
Let me know!
Who use DPlayer?
- 学习强国: “学习强国”学习平台精心打造的手机客户端
- 小红书: 中国最大的生活社区分享平台,同时也是发现全球好物的电商平台
- 极客时间: 极客邦科技出品的一款 IT 内容知识服务 App
- 嘀哩嘀哩: 兴趣使然的无名小站(D 站)
- 银色子弹: 银色子弹,简称银弹,由多数柯南热爱者聚集在一起的组织
- 浙江大学 CC98 论坛: 浙江大学校网内规模最大的论坛,中国各大学中较活跃的 BBS 之一
- 纸飞机南航青年网络社区: 南京航空航天大学门户网站
- otomads: 专注于音 MAD 的视频弹幕网站
- Cloudreve: 基于 ThinkPHP 构建的网盘系统
- oneindex: Onedrive Directory Index
- arozos: General purposed Web Desktop Operating Platform / OS for Raspberry Pis
- 新东方云教室
- BBHouse: A Bilibili Cross-Platform Desktop Client Powered By Tauri
- Tampermonkey 阿里云盘
- arozos
- GBCLStudio/fof-upload-qcloud
- Feel free to submit yours in
Let me know!
Donate
DPlayer is an MIT licensed open source project and completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing.
You can support DPlayer via donations.
Recurring Donation
- Become a Sponser on GitHub
- Become a Sponser on Patreon
- Become a Sponser on 爱发电
- Contact us directly: [email protected]
One-time Donation
We accept donations via the following ways:
Author
DPlayer © DIYgod, Released under the MIT License.
Authored and maintained by DIYgod with help from contributors (list).
Blog · GitHub @DIYgod · Twitter @DIYgod · Telegram Channel @awesomeDIYgod
File: docs/zh/ecosystem.md
sidebar: auto
生态
让 DPlayer 变得更好,请随意在 Let me know! 提交你的项目和产品
帮助
提交 issue
相关项目
工具
- DPlayer-thumbnails: generate video thumbnails
弹幕接口
- DPlayer-node: Node.js
- laravel-danmaku: PHP
- dplayer-live-backend: Node.js, WebSocket live backend
- RailsGun: Ruby
插件
- DPlayer-for-typecho: Typecho
- Hexo-tag-dplayer: Hexo
- DPlayer_for_Z-BlogPHP: Z-BlogPHP
- DPlayer for Discuz!: Discuz!
- DPlayer for WordPress: WordPress
- DPlayerHandle: WordPress
- Selection: WordPress
- Vue-DPlayer: Vue
- react-dplayer: React
- rc-dplayer: React
其他
- DPlayer-Lite: lite version
- hlsjs-p2p-engine
谁在用 DPlayer?
- 学习强国: “学习强国”学习平台精心打造的手机客户端
- 小红书: 中国最大的生活社区分享平台,同时也是发现全球好物的电商平台
- 极客时间: 极客邦科技出品的一款 IT 内容知识服务 App
- 嘀哩嘀哩: 兴趣使然的无名小站(D 站)
- 银色子弹: 银色子弹,简称银弹,由多数柯南热爱者聚集在一起的组织
- 浙江大学 CC98 论坛: 浙江大学校网内规模最大的论坛,中国各大学中较活跃的 BBS 之一
- 纸飞机南航青年网络社区: 南京航空航天大学门户网站
- otomads: 专注于音 MAD 的视频弹幕网站
- Cloudreve: 基于 ThinkPHP 构建的网盘系统
- arozos: General purposed Web Desktop Operating Platform / OS for Raspberry Pis
- 新东方云教室
- BBHouse: A Bilibili Cross-Platform Desktop Client Powered By Tauri
- Tampermonkey 阿里云盘
- arozos
- GBCLStudio/fof-upload-qcloud
- Feel free to submit yours in
Let me know!
File: docs/zh/guide.md
sidebar: auto
指南
DPlayer
🍭 Wow, such a lovely HTML5 danmaku video player
Special Thanks
Sponsors
安装
使用 npm:
npm install dplayer --save使用 Yarn:
yarn add dplayer快速开始
我们先尝试初始化一个最简单的 DPlayer
加载播放器文件:
<script src="DPlayer.min.js"></script>或者使用模块管理器:
import DPlayer from 'dplayer';
const dp = new DPlayer(options);在 js 里初始化:
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.mp4',
},
});一个最简单的 DPlayer 就初始化好了,它只有最基本的视频播放功能
参数
DPlayer 有丰富的参数可以自定义你的播放器实例
| 名称 | 默认值 | 描述 |
|---|---|---|
| container | document.querySelector('.dplayer') | 播放器容器元素 |
| live | false | 开启直播模式, 见#直播 |
| autoplay | false | 视频自动播放 |
| theme | '#b7daff' | 主题色 |
| loop | false | 视频循环播放 |
| lang | navigator.language.toLowerCase() | 可选值: 'en', 'zh-cn', 'zh-tw' |
| screenshot | false | 开启截图,如果开启,视频和视频封面需要允许跨域 |
| hotkey | true | 开启热键,支持快进、快退、音量控制、播放暂停 |
| airplay | false | 在 Safari 中开启 AirPlay |
| chromecast | false | 启用 Chromecast |
| preload | 'auto' | 视频预加载,可选值: 'none', 'metadata', 'auto' |
| volume | 0.7 | 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 |
| playbackSpeed | [0.5, 0.75, 1, 1.25, 1.5, 2] | 可选的播放速率,可以设置成自定义的数组 |
| logo | - | 在左上角展示一个 logo,你可以通过 CSS 调整它的大小和位置 |
| apiBackend | - | 自定义获取和发送弹幕行为,见#直播 |
| preventClickToggle | false | 阻止点击播放器时候自动切换播放/暂停 |
| video | - | 视频信息 |
| video.quality | - | 见#清晰度切换 |
| video.defaultQuality | - | 见#清晰度切换 |
| video.url | - | 视频链接 |
| video.pic | - | 视频封面 |
| video.thumbnails | - | 视频缩略图,可以使用 DPlayer-thumbnails 生成 |
| video.type | 'auto' | 可选值: 'auto', 'hls', 'flv', 'dash', 'webtorrent', 'normal' 或其他自定义类型, 见#MSE 支持 |
| video.customType | - | 自定义类型, 见#MSE 支持 |
| subtitle | - | 外挂字幕 |
| subtitle.url | required |
字幕链接 |
| subtitle.type | 'webvtt' | 字幕类型,可选值: 'webvtt', 'ass',目前只支持 webvtt |
| subtitle.fontSize | '20px' | 字幕字号 |
| subtitle.bottom | '40px' | 字幕距离播放器底部的距离,取值形如: '10px' '10%' |
| subtitle.color | '#fff' | 字幕颜色 |
| danmaku | - | 显示弹幕 |
| danmaku.id | required |
弹幕池 id,必须唯一 |
| danmaku.api | required |
见#弹幕接口 |
| danmaku.token | - | 弹幕后端验证 token |
| danmaku.maximum | - | 弹幕最大数量 |
| danmaku.addition | - | 额外外挂弹幕,见#bilibili 弹幕 |
| danmaku.user | 'DIYgod' | 弹幕用户名 |
| danmaku.bottom | - | 弹幕距离播放器底部的距离,防止遮挡字幕,取值形如: '10px' '10%' |
| danmaku.unlimited | false | 海量弹幕模式,即使重叠也展示全部弹幕,请注意播放器会记忆用户设置,用户手动设置后即失效 |
| danmaku.speedRate | 1 | 弹幕速度倍率,越大速度越快 |
| contextmenu | [] | 自定义右键菜单 |
| highlight | [] | 自定义进度条提示点 |
| mutex | true | 互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 |
const dp = new DPlayer({
container: document.getElementById('dplayer'),
autoplay: false,
theme: '#FADFA3',
loop: true,
lang: 'zh-cn',
screenshot: true,
hotkey: true,
preload: 'auto',
logo: 'logo.png',
volume: 0.7,
mutex: true,
video: {
url: 'dplayer.mp4',
pic: 'dplayer.png',
thumbnails: 'thumbnails.jpg',
type: 'auto',
},
subtitle: {
url: 'dplayer.vtt',
type: 'webvtt',
fontSize: '25px',
bottom: '10%',
color: '#b7daff',
},
danmaku: {
id: '9E2E3368B56CDBB4',
api: 'https://api.prprpr.me/dplayer/',
token: 'tokendemo',
maximum: 1000,
addition: ['https://api.prprpr.me/dplayer/v3/bilibili?aid=4157142'],
user: 'DIYgod',
bottom: '15%',
unlimited: true,
speedRate: 0.5,
},
contextmenu: [
{
text: 'custom1',
link: 'https://github.com/DIYgod/DPlayer',
},
{
text: 'custom2',
click: (player) => {
console.log(player);
},
},
],
highlight: [
{
time: 20,
text: '这是第 20 秒',
},
{
time: 120,
text: '这是 2 分钟',
},
],
});API
dp.play(): 播放视频dp.pause(): 暂停视频dp.seek(time: number): 跳转到特定时间jsdp.seek(100);dp.toggle(): 切换播放和暂停dp.on(event: string, handler: function): 绑定视频和播放器事件,见#事件绑定dp.switchVideo(video, danmaku): 切换到其他视频jsdp.switchVideo( { url: 'second.mp4', pic: 'second.png', thumbnails: 'second.jpg', }, { id: 'test', api: 'https://api.prprpr.me/dplayer/', maximum: 3000, user: 'DIYgod', } );dp.notice(text: string, time: number): 显示通知,时间的单位为毫秒,默认时间 2000 毫秒,默认透明度 0.8dp.switchQuality(index: number): 切换清晰度dp.destroy(): 销毁播放器dp.speed(rate: number): 设置视频速度dp.volume(percentage: number, nostorage: boolean, nonotice: boolean): 设置视频音量jsdp.volume(0.1, true, false);dp.video: 原生 videodp.video.currentTime: 返回视频当前播放时间dp.video.duration: 返回视频总时间dp.video.paused: 返回视频是否暂停支持大多数原生 video 接口
dp.danmakudp.danmaku.send(danmaku, callback: function): 提交一个新弹幕jsdp.danmaku.send( { text: 'dplayer is amazing', color: '#b7daff', type: 'right', // should be `top` `bottom` or `right` }, function () { console.log('success'); } );dp.danmaku.draw(danmaku): 实时绘制一个新弹幕jsdp.danmaku.draw({ text: 'DIYgod is amazing', color: '#fff', type: 'top', });dp.danmaku.opacity(percentage: number): 设置弹幕透明度,透明度值在 0 到 1 之间jsdp.danmaku.opacity(0.5);dp.danmaku.clear(): 清除所有弹幕dp.danmaku.hide(): 隐藏弹幕dp.danmaku.show(): 显示弹幕dp.fullScreen: 两个类型:web和browser,默认类型是browserdp.fullScreen.request(type: string): 进入全屏jsdp.fullScreen.request('web');dp.fullScreen.cancel(type: string): 退出全屏jsdp.fullScreen.cancel('web');
事件绑定
dp.on(event, handler)
dp.on('ended', function () {
console.log('player ended');
});视频事件
- abort
- canplay
- canplaythrough
- durationchange
- emptied
- ended
- error
- loadeddata
- loadedmetadata
- loadstart
- mozaudioavailable
- pause
- play
- playing
- progress
- ratechange
- seeked
- seeking
- stalled
- suspend
- timeupdate
- volumechange
- waiting
播放器事件
- screenshot
- thumbnails_show
- thumbnails_hide
- danmaku_show
- danmaku_hide
- danmaku_clear
- danmaku_loaded
- danmaku_send
- danmaku_opacity
- contextmenu_show
- contextmenu_hide
- notice_show
- notice_hide
- quality_start
- quality_end
- destroy
- resize
- fullscreen
- fullscreen_cancel
- subtitle_show
- subtitle_hide
- subtitle_change
清晰度切换
在 video.quality 里设置不同清晰度的视频链接和类型,video.defaultQuality 设置默认清晰度
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
quality: [
{
name: 'HD',
url: 'demo.m3u8',
type: 'hls',
},
{
name: 'SD',
url: 'demo.mp4',
type: 'normal',
},
],
defaultQuality: 0,
pic: 'demo.png',
thumbnails: 'thumbnails.jpg',
},
});在使用 customType 配合其他 MSE 库使用时,需要监听 destroy 和 quality_end 事件及时销毁 MSE 库实例,避免内存泄漏
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
quality: [
{
name: 'HD',
url: 'demo_hd.m3u8',
type: 'Hls',
},
{
name: 'SD',
url: 'demo_sd.m3u8',
type: 'Hls',
},
],
defaultQuality: 0,
customType: {
Hls: (video, player) => {
const hls = new window.Hls();
hls.loadSource(video.src);
hls.attachMedia(video);
hls.sessionId = crypto.randomUUID();
player.sessionId = hls.sessionId;
player.events.on('destroy', () => {
hls.destroy();
});
player.events.on('quality_end', () => {
if (hls.sessionId !== player.sessionId) {
hls.destroy();
}
});
},
},
},
});弹幕
弹幕接口
danmaku.api
每日备份: DPlayer-data
自己搭建
bilibili 弹幕
danmaku.addition
API: https://api.prprpr.me/dplayer/v3/bilibili?aid=[aid]
const option = {
danmaku: {
// ...
addition: ['https://api.prprpr.me/dplayer/v3/bilibili?aid=[aid]'],
},
};MSE 支持
HLS
需要在 DPlayer.min.js 前面加载 hls.js。
<script src="hls.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.m3u8',
type: 'hls',
},
pluginOptions: {
hls: {
// hls config
},
},
});
console.log(dp.plugins.hls); // Hls 实例// 另一种方式,使用 customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.m3u8',
type: 'customHls',
customType: {
customHls: function (video, player) {
const hls = new Hls();
hls.loadSource(video.src);
hls.attachMedia(video);
},
},
},
});MPEG DASH
需要在 DPlayer.min.js 前面加载 dash.js。
<script src="dash.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.mpd',
type: 'dash',
},
pluginOptions: {
dash: {
// dash config
},
},
});
console.log(dp.plugins.dash); // Dash 实例// 另一种方式,使用 customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.mpd',
type: 'customDash',
customType: {
customDash: function (video, player) {
dashjs.MediaPlayer().create().initialize(video, video.src, false);
},
},
},
});MPEG DASH (Shaka)
需要在 DPlayer.min.js 前面加载 shaka-player.compiled.js。
<script src="shaka-player.compiled.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
screenshot: true,
video: {
url: 'demo.mpd',
type: 'shakaDash',
customType: {
shakaDash: function (video, player) {
var src = video.src;
var playerShaka = new shaka.Player(video); // 将会修改 video.src
playerShaka.load(src);
},
},
},
});FLV
需要在 DPlayer.min.js 前面加载 flv.js。
<script src="flv.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.flv',
type: 'flv',
},
pluginOptions: {
flv: {
// refer to https://github.com/bilibili/flv.js/blob/master/docs/api.md#flvjscreateplayer
mediaDataSource: {
// mediaDataSource config
},
config: {
// config
},
},
},
});
console.log(dp.plugins.flv); // flv 实例// 另一种方式,使用 customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.flv',
type: 'customFlv',
customType: {
customFlv: function (video, player) {
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: video.src,
});
flvPlayer.attachMediaElement(video);
flvPlayer.load();
},
},
},
});WebTorrent
需要在 DPlayer.min.js 前面加载 webtorrent。
<script src="webtorrent.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'magnet:demo',
type: 'webtorrent',
},
pluginOptions: {
webtorrent: {
// webtorrent config
},
},
});
console.log(dp.plugins.webtorrent); // WebTorrent 实例// 另一种方式,使用 customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'magnet:demo',
type: 'customWebTorrent',
customType: {
customWebTorrent: function (video, player) {
player.container.classList.add('dplayer-loading');
const client = new WebTorrent();
const torrentId = video.src;
client.add(torrentId, (torrent) => {
const file = torrent.files.find((file) => file.name.endsWith('.mp4'));
file.renderTo(
video,
{
autoplay: player.options.autoplay,
},
() => {
player.container.classList.remove('dplayer-loading');
}
);
});
},
},
},
});配合其他 MSE 库使用
DPlayer 可以通过 customType 参数与任何 MSE 库一起使用,例如支持 P2P 插件:
<script src="https://cdn.jsdelivr.net/npm/cdnbye@latest"></script>
<script src="DPlayer.min.js"></script>var type = 'normal';
if (Hls.isSupported() && Hls.WEBRTC_SUPPORT) {
type = 'customHls';
}
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.m3u8',
type: type,
customType: {
customHls: function (video, player) {
const hls = new Hls({
debug: false,
// Other hlsjsConfig options provided by hls.js
p2pConfig: {
live: false, // 如果是直播设为true
// Other p2pConfig options provided by CDNBye http://www.cdnbye.com/cn/
},
});
hls.loadSource(video.src);
hls.attachMedia(video);
},
},
},
});直播
你可以把 DPlayer 用在直播当中,但如果你想要直播弹幕,你需要自己准备一个 WebSocket 后端。
初始化播放器:
const dp = new DPlayer({
container: document.getElementById('dplayer'),
live: true,
danmaku: true,
apiBackend: {
read: function (options) {
console.log('Pretend to connect WebSocket');
options.success([]);
},
send: function (options) {
console.log('Pretend to send danmaku via WebSocket', options.data);
options.success();
},
},
video: {
url: 'demo.m3u8',
type: 'hls',
},
});通过 WebSocket 获取到弹幕之后,通过 dp.danmaku.draw 绘制弹幕:
const danmaku = {
text: 'Get a danmaku via WebSocket',
color: '#fff',
type: 'right',
};
dp.danmaku.draw(danmaku);常见问题
为什么播放器不能全屏?
如果播放器被包含在 iframe 里,尝试在 iframe 上添加 allowfullscreen 属性。
为了完善的浏览器兼容性,它应该是这样:
为什么播放器不能在手机上自动播放?
大多数移动端浏览器禁止了视频自动播放。
File: docs/zh/README.md
home: true actionText: Get Started → actionLink: /zh/guide/ footer: MIT Licensed | Made with love by DIYgod
File: docs/zh/support.md
sidebar: auto
赞助 DPlayer 的研发
DPlayer 是采用 MIT 许可的开源项目,使用完全免费。 但是随着项目规模的增长,也需要有相应的资金支持才能持续项目的维护的开发。
如果你是企业经营者并且将 DPlayer 用在商业产品中,那么赞助 DPlayer 有商业上的益处:可以让你的产品所依赖的框架保持健康并得到积极的维护。
如果你是个人开发者并且享受 DPlayer 带来的高开发效率,可以用捐助来表示你的谢意 —— 比如偶尔给我买杯咖啡 :)
你可以通过下列的方法来赞助 DPlayer 的开发.
周期性赞助
一次性赞助
我们通过以下方式接受赞助:
赞助商
DPlayer 贡献者
感谢所有贡献者。
File: docs/ecosystem.md
sidebar: auto
Ecosystem
Let's make DPlayer better, feel free to submit yours in Let me know!
Help
Creating issue
Related Projects
Tooling
- DPlayer-thumbnails: generate video thumbnails
Danmaku api
- DPlayer-node: Node.js
- laravel-danmaku: PHP
- dplayer-live-backend: Node.js, WebSocket live backend
- RailsGun: Ruby
Plugins
- DPlayer-for-typecho: Typecho
- Hexo-tag-dplayer: Hexo
- DPlayer_for_Z-BlogPHP: Z-BlogPHP
- DPlayer for Discuz!: Discuz!
- DPlayer for WordPress: WordPress
- DPlayerHandle: WordPress
- Selection: WordPress
- Vue-DPlayer: Vue
- react-dplayer: React
- rc-dplayer: React
Other
- DPlayer-Lite: lite version
- hlsjs-p2p-engine
Who use DPlayer?
- 学习强国: “学习强国”学习平台精心打造的手机客户端
- 小红书: 中国最大的生活社区分享平台,同时也是发现全球好物的电商平台
- 极客时间: 极客邦科技出品的一款 IT 内容知识服务 App
- 嘀哩嘀哩: 兴趣使然的无名小站(D 站)
- 银色子弹: 银色子弹,简称银弹,由多数柯南热爱者聚集在一起的组织
- 浙江大学 CC98 论坛: 浙江大学校网内规模最大的论坛,中国各大学中较活跃的 BBS 之一
- 纸飞机南航青年网络社区: 南京航空航天大学门户网站
- otomads: 专注于音 MAD 的视频弹幕网站
- Cloudreve: 基于 ThinkPHP 构建的网盘系统
- arozos: General purposed Web Desktop Operating Platform / OS for Raspberry Pis
- 新东方云教室
- BBHouse: A Bilibili Cross-Platform Desktop Client Powered By Tauri
- Tampermonkey 阿里云盘
- arozos
- GBCLStudio/fof-upload-qcloud
- Feel free to submit yours in
Let me know!
Contributors
This project exists thanks to all the people who contribute.
File: docs/guide.md
sidebar: auto
Guide
DPlayer
🍭 Wow, such a lovely HTML5 danmaku video player
Special Thanks
Sponsors
Installation
Using npm:
npm install dplayer --saveUsing Yarn:
yarn add dplayerQuick Start
At first, let's initialize a simplest DPlayer
Load DPlayer files
<script src="DPlayer.min.js"></script>Or work with module bundler:
import DPlayer from 'dplayer';
const dp = new DPlayer(options);Initialization in js:
const dp = new DPlayer({
container: document.getElementById('dplayer'),
screenshot: true,
video: {
url: 'demo.mp4',
pic: 'demo.jpg',
thumbnails: 'thumbnails.jpg',
},
subtitle: {
url: 'webvtt.vtt',
},
danmaku: {
id: 'demo',
api: 'https://api.prprpr.me/dplayer/',
},
});Options
You can custom your player instance by those options
| Name | Default | Description |
|---|---|---|
| container | document.querySelector('.dplayer') | player container |
| live | false | enable live mode, see #live |
| autoplay | false | video autoplay |
| theme | '#b7daff' | main color |
| loop | false | video loop |
| lang | navigator.language.toLowerCase() | values: 'en', 'zh-cn', 'zh-tw' |
| screenshot | false | enable screenshot, if true, video and video poster must enable Cross-Origin |
| airplay | false | enable airplay in Safari |
| chromecast | false | enable Chromecast |
| hotkey | true | enable hotkey, support FF, FR, volume control, play & pause |
| preload | 'auto' | values: 'none', 'metadata', 'auto' |
| volume | 0.7 | default volume, notice that player will remember user setting, default volume will not work after user set volume themselves |
| playbackSpeed | [0.5, 0.75, 1, 1.25, 1.5, 2] | optional playback speed, or or you can set a custom one |
| logo | - | showing logo in the top left corner, you can adjust its size and position by CSS |
| apiBackend | - | getting and sending danmaku in your way, see #live |
| preventClickToggle | false | prevent toggle video play/pause status when click player |
| video | - | video info |
| video.quality | - | see #Quality switching |
| video.defaultQuality | - | see #Quality switching |
| video.url | - | video url |
| video.pic | - | video poster |
| video.thumbnails | - | video thumbnails, generated by DPlayer-thumbnails |
| video.type | 'auto' | values: 'auto', 'hls', 'flv', 'dash', 'webtorrent', 'normal' or other custom type, see #MSE support |
| video.customType | - | custom video type, see #MSE support |
| subtitle | - | external subtitle |
| subtitle.url | required |
subtitle url |
| subtitle.type | 'webvtt' | subtitle type, values: 'webvtt', 'ass', but only webvtt is supported for now |
| subtitle.fontSize | '20px' | subtitle font size |
| subtitle.bottom | '40px' | the distance between the subtitle and player bottom, values like: '10px' '10%' |
| subtitle.color | '#fff' | subtitle color |
| danmaku | - | showing danmaku |
| danmaku.id | required |
danmaku pool id, it must be unique |
| danmaku.api | required |
see #Danmaku API |
| danmaku.token | - | back end verification token |
| danmaku.maximum | - | danmaku maximum quantity |
| danmaku.addition | - | additional danmaku, see #bilibili danmaku |
| danmaku.user | 'DIYgod' | danmaku user name |
| danmaku.bottom | - | values like: '10px' '10%', the distance between the danmaku bottom and player bottom, in order to prevent warding off subtitle |
| danmaku.unlimited | false | display all danmaku even though danmaku overlap, notice that player will remember user setting, default setting will not work after user set it themselves |
| danmaku.speedRate | 1 | danmaku speed multiplier, the larger the faster |
| contextmenu | [] | custom contextmenu |
| highlight | [] | custom time markers upon progress bar |
| mutex | true | prevent to play multiple player at the same time, pause other players when this player start play |
const dp = new DPlayer({
container: document.getElementById('dplayer'),
autoplay: false,
theme: '#FADFA3',
loop: true,
lang: 'zh-cn',
screenshot: true,
hotkey: true,
preload: 'auto',
logo: 'logo.png',
volume: 0.7,
mutex: true,
video: {
url: 'dplayer.mp4',
pic: 'dplayer.png',
thumbnails: 'thumbnails.jpg',
type: 'auto',
},
subtitle: {
url: 'dplayer.vtt',
type: 'webvtt',
fontSize: '25px',
bottom: '10%',
color: '#b7daff',
},
danmaku: {
id: '9E2E3368B56CDBB4',
api: 'https://api.prprpr.me/dplayer/',
token: 'tokendemo',
maximum: 1000,
addition: ['https://api.prprpr.me/dplayer/v3/bilibili?aid=4157142'],
user: 'DIYgod',
bottom: '15%',
unlimited: true,
speedRate: 0.5,
},
contextmenu: [
{
text: 'custom1',
link: 'https://github.com/DIYgod/DPlayer',
},
{
text: 'custom2',
click: (player) => {
console.log(player);
},
},
],
highlight: [
{
text: 'marker for 20s',
time: 20,
},
{
text: 'marker for 2mins',
time: 120,
},
],
});API
dp.play(): play videodp.pause(): pause videodp.seek(time: number): seek to specified timejsdp.seek(100);dp.toggle(): toggle between play and pausedp.on(event: string, handler: function): bind video and player events, see more detailsdp.switchVideo(video, danmaku): switch to a new videojsdp.switchVideo( { url: 'second.mp4', pic: 'second.png', thumbnails: 'second.jpg', }, { id: 'test', api: 'https://api.prprpr.me/dplayer/', maximum: 3000, user: 'DIYgod', } );dp.notice(text: string, time: number, opacity: number): show message, the unit of time is millisecond, the default of time is 2000, the default of opacity is 0.8jsdp.notice('Amazing player', 2000, 0.8);dp.switchQuality(index: number): switch qualitydp.destroy(): destroy playerdp.speed(rate: number): set video speeddp.volume(percentage: number, nostorage: boolean, nonotice: boolean): set video volumejsdp.volume(0.1, true, false);dp.video: native videodp.video.currentTime: returns the current playback positiondp.video.duration: returns video total timedp.video.paused: returns whether the video pausedmost native api are supported
dp.danmakudp.danmaku.send(danmaku, callback: function): submit a new danmaku to back endjsdp.danmaku.send( { text: 'dplayer is amazing', color: '#b7daff', type: 'right', // should be `top` `bottom` or `right` }, function () { console.log('success'); } );dp.danmaku.draw(danmaku): draw a new danmaku to player in real timejsdp.danmaku.draw({ text: 'DIYgod is amazing', color: '#fff', type: 'top', });dp.danmaku.opacity(percentage: number): set danmaku opacity, opacity should between 0 and 1jsdp.danmaku.opacity(0.5);dp.danmaku.clear(): clear all danmakusdp.danmaku.hide(): hide danmakudp.danmaku.show(): show danmakudp.fullScreen: two type:weborbrowser, the default one isbrowserdp.fullScreen.request(type: string): request fullscreenjsdp.fullScreen.request('web');dp.fullScreen.cancel(type: string): cancel fullscreenjsdp.fullScreen.cancel('web');
Event binding
dp.on(event, handler)
dp.on('ended', function () {
console.log('player ended');
});Video events
- abort
- canplay
- canplaythrough
- durationchange
- emptied
- ended
- error
- loadeddata
- loadedmetadata
- loadstart
- mozaudioavailable
- pause
- play
- playing
- progress
- ratechange
- seeked
- seeking
- stalled
- suspend
- timeupdate
- volumechange
- waiting
Player events
- screenshot
- thumbnails_show
- thumbnails_hide
- danmaku_show
- danmaku_hide
- danmaku_clear
- danmaku_loaded
- danmaku_send
- danmaku_opacity
- contextmenu_show
- contextmenu_hide
- notice_show
- notice_hide
- quality_start
- quality_end
- destroy
- resize
- fullscreen
- fullscreen_cancel
- webfullscreen
- webfullscreen_cancel
- subtitle_show
- subtitle_hide
- subtitle_change
Quality switching
Set video url and video type in video.quality, set default quality by video.defaultQuality.
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
quality: [
{
name: 'HD',
url: 'demo.m3u8',
type: 'hls',
},
{
name: 'SD',
url: 'demo.mp4',
type: 'normal',
},
],
defaultQuality: 0,
pic: 'demo.png',
thumbnails: 'thumbnails.jpg',
},
});When using customType (Work with other MSE library), you should listen for the destroy and quality_end events to destroy the MSE library instance in a timely manner to avoid memory leaks.
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
quality: [
{
name: 'HD',
url: 'demo_hd.m3u8',
type: 'Hls',
},
{
name: 'SD',
url: 'demo_sd.m3u8',
type: 'Hls',
},
],
defaultQuality: 0,
customType: {
Hls: (video, player) => {
const hls = new window.Hls();
hls.loadSource(video.src);
hls.attachMedia(video);
hls.sessionId = crypto.randomUUID();
player.sessionId = hls.sessionId;
player.events.on('destroy', () => {
hls.destroy();
});
player.events.on('quality_end', () => {
if (hls.sessionId !== player.sessionId) {
hls.destroy();
}
});
},
},
},
});Danmaku
Danmaku API
danmaku.api
Daily backup data: DPlayer-data
Setting up yourself
bilibili danmaku
danmaku.addition
API: https://api.prprpr.me/dplayer/v3/bilibili?aid=[aid]
const option = {
danmaku: {
// ...
addition: ['https://api.prprpr.me/dplayer/v3/bilibili?aid=[aid]'],
},
};MSE support
HLS
It requires the library hls.js and it should be loaded before DPlayer.min.js.
<script src="hls.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.m3u8',
type: 'hls',
},
pluginOptions: {
hls: {
// hls config
},
},
});
console.log(dp.plugins.hls); // Hls instance// another way, use customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.m3u8',
type: 'customHls',
customType: {
customHls: function (video, player) {
const hls = new Hls();
hls.loadSource(video.src);
hls.attachMedia(video);
},
},
},
});MPEG DASH
It requires the library dash.js and it should be loaded before DPlayer.min.js.
<script src="dash.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.mpd',
type: 'dash',
},
pluginOptions: {
dash: {
// dash config
},
},
});
console.log(dp.plugins.dash); // Dash instance// another way, use customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.mpd',
type: 'customDash',
customType: {
customDash: function (video, player) {
dashjs.MediaPlayer().create().initialize(video, video.src, false);
},
},
},
});MPEG DASH (Shaka)
It requires the library shaka-player and it should be loaded before DPlayer.min.js.
<script src="shaka-player.compiled.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
screenshot: true,
video: {
url: 'demo.mpd',
type: 'shakaDash',
customType: {
shakaDash: function (video, player) {
var src = video.src;
var playerShaka = new shaka.Player(video); // 将会修改 video.src
playerShaka.load(src);
},
},
},
});FLV
It requires the library flv.js and it should be loaded before DPlayer.min.js.
<script src="flv.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.flv',
type: 'flv',
},
pluginOptions: {
flv: {
// refer to https://github.com/bilibili/flv.js/blob/master/docs/api.md#flvjscreateplayer
mediaDataSource: {
// mediaDataSource config
},
config: {
// config
},
},
},
});
console.log(dp.plugins.flv); // flv instance// another way, use customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.flv',
type: 'customFlv',
customType: {
customFlv: function (video, player) {
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: video.src,
});
flvPlayer.attachMediaElement(video);
flvPlayer.load();
},
},
},
});WebTorrent
It requires the library webtorrent and it should be loaded before DPlayer.min.js.
<script src="webtorrent.min.js"></script>
<script src="DPlayer.min.js"></script>const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'magnet:demo',
type: 'webtorrent',
},
pluginOptions: {
webtorrent: {
// webtorrent config
},
},
});
console.log(dp.plugins.webtorrent); // WebTorrent instance// another way, use customType
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'magnet:demo',
type: 'customWebTorrent',
customType: {
customWebTorrent: function (video, player) {
player.container.classList.add('dplayer-loading');
const client = new WebTorrent();
const torrentId = video.src;
client.add(torrentId, (torrent) => {
const file = torrent.files.find((file) => file.name.endsWith('.mp4'));
file.renderTo(
video,
{
autoplay: player.options.autoplay,
},
() => {
player.container.classList.remove('dplayer-loading');
}
);
});
},
},
},
});Work with other MSE library
DPlayer can work with any MSE library via customType option.
<script src="https://cdn.jsdelivr.net/npm/cdnbye@latest"></script>
<script src="DPlayer.min.js"></script>var type = 'normal';
if (Hls.isSupported() && Hls.WEBRTC_SUPPORT) {
type = 'customHls';
}
const dp = new DPlayer({
container: document.getElementById('dplayer'),
video: {
url: 'demo.m3u8',
type: type,
customType: {
customHls: function (video, player) {
const hls = new Hls({
debug: false,
// Other hlsjsConfig options provided by hls.js
p2pConfig: {
live: false,
// Other p2pConfig options provided by CDNBye http://www.cdnbye.com/en/
},
});
hls.loadSource(video.src);
hls.attachMedia(video);
},
},
},
});Live
You can use DPlayer in live, but if you want live danmaku, you should prepare a WebSocket backend yourself.
Init player:
const dp = new DPlayer({
container: document.getElementById('dplayer'),
live: true,
danmaku: true,
apiBackend: {
read: function (options) {
console.log('Pretend to connect WebSocket');
options.success([]);
},
send: function (options) {
console.log('Pretend to send danmaku via WebSocket', options.data);
options.success();
},
},
video: {
url: 'demo.m3u8',
type: 'hls',
},
});Draw danmaku after getting a danmaku via WebSocket:
const danmaku = {
text: 'Get a danmaku via WebSocket',
color: '#fff',
type: 'right',
};
dp.danmaku.draw(danmaku);FAQ
Why can't player be full screen?
If player is contained in a iframe, try adding the allowfullscreen attribute to the iframe.
For full browser support it should look like this:
Why can't player autoplay in some mobile browsers?
Most mobile browsers forbid video autoplay, you wont be able to achieve it without hacks.
File: docs/README.md
home: true actionText: Get Started → actionLink: /guide/ footer: MIT Licensed | Made with love by DIYgod
File: docs/support.md
sidebar: auto
Sponsor DPlayer Development
DPlayer is an MIT licensed open source project and completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing.
If you run a business and are using DPlayer in a revenue-generating product, it makes business sense to sponsor DPlayer development: it ensures the project that your product relies on stays healthy and actively maintained.
If you are an individual user and have enjoyed the productivity of using DPlayer, consider donating as a sign of appreciation - like buying me coffee once in a while :)
You can support DPlayer via donations.
Recurring Donation
Recurring donors will be rewarded via express issue response, or even have your name displayed on our GitHub page and website.
- Become a Sponser on GitHub
- Become a Sponser on Patreon
- Become a Sponser on 爱发电
- Contact us directly: [email protected]
One-time Donation
We accept donations via the following ways:
Sponsors
DPlayer contributors
This project exists thanks to all the people who contribute.
2. Official Technical Reference & Guides (DIYgod/DIYgod.github.io)
A Diary Generator
Reads diaries written in markdown from a git submodule, and generates a static site for it. (Demo)
About the repos
The markdown files for the diaries can be kept under another repo named YYYY/MM/DDDD.md(Example).
Build
- Run
npm installto install the dependencies - Configure
config.js git checkout -b yournamefor your own branch(so you can keep the master branch intact in case you want to receive updates)git rm diaryto remove the old submodule for diariesgit submodule add git://new/submodule.git diaryto add your own submodule- Commit the changes (to your own branch) if you want.
- Run
gulp buildto generate the static site (placed underdist). - Run
gulp serverand visithttp://localhost:8000/diaryif you want to see it hosted locally(make sure the port 8000 is not taken).
You can receive updates by pulling updates into your master branch, and check them out to your own branch.
Deploy to GitHub Pages
- Set up the SSH git remote
originfor the project. - After building the web page, run
gulp deploy. - Everything under dist will be pushed to the remote repo's gh-pages branch.
Develop
- Make sure port 35729(for livereload) and 8000(for the local server) are available.
- Run
gulp, then visithttp://localhost:8000/diary. - Start development!
- When you are done, you can checkout the changes from your branch to the master branch, and send in a pull request if you want.
TODO
- Write a calendar to replace pikaday
- Add "previous" and "next" button to the diary pages
LICENSE
(MIT License)
Copyright (c) 2015 Joyee Cheung
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.