Compare commits
358 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
bc43cc0ac2 | |
|
|
c07900cb8d | |
|
|
3fd7896375 | |
|
|
f00e304ca3 | |
|
|
445388037d | |
|
|
44d35f6acc | |
|
|
0a026a4002 | |
|
|
c05bd08afa | |
|
|
3cf3e4be36 | |
|
|
2e9b87f019 | |
|
|
7977068e35 | |
|
|
80b9b01a16 | |
|
|
a415527038 | |
|
|
3e799a02c4 | |
|
|
b0ba40b90e | |
|
|
9ca1c1ebd4 | |
|
|
cb1cadbc79 | |
|
|
6c1336448b | |
|
|
4f6109192a | |
|
|
cb6408a943 | |
|
|
255bbac7a4 | |
|
|
6e780e048d | |
|
|
ef90da3254 | |
|
|
46722004d6 | |
|
|
602f8fdca9 | |
|
|
1dc5acf755 | |
|
|
b83195db10 | |
|
|
1b1b6da6e3 | |
|
|
81bd218e58 | |
|
|
bdb16d9bb3 | |
|
|
d833e2c835 | |
|
|
a0424ca303 | |
|
|
d905e0ed4b | |
|
|
4357a7d780 | |
|
|
20517bd5f0 | |
|
|
5e54f83d79 | |
|
|
7808f5c424 | |
|
|
99c880f436 | |
|
|
d9b7c1934f | |
|
|
e80b99de5a | |
|
|
dc679fee6d | |
|
|
360a35f1c4 | |
|
|
064dccdff3 | |
|
|
d1c32f66db | |
|
|
2b6b46e5f6 | |
|
|
ef273ec42a | |
|
|
b429b9a5b7 | |
|
|
52e962736b | |
|
|
32c389a8b5 | |
|
|
ad4a1a78be | |
|
|
455af3385f | |
|
|
b16e54049b | |
|
|
414a035cef | |
|
|
0634b3df99 | |
|
|
6d7d9f34f1 | |
|
|
c162fcc045 | |
|
|
69dfac4fc0 | |
|
|
14fdd9353c | |
|
|
be9bb1f064 | |
|
|
04b000206f | |
|
|
fccdda6d47 | |
|
|
501525cc7c | |
|
|
af4efc3182 | |
|
|
6864587010 | |
|
|
2143a266d9 | |
|
|
14afb2a366 | |
|
|
367c1c818c | |
|
|
91da373e58 | |
|
|
b974065ea4 | |
|
|
b6560870eb | |
|
|
1f512ef616 | |
|
|
fa4835d750 | |
|
|
ba61ce3dfb | |
|
|
a25d7d4da9 | |
|
|
3fb5f1b152 | |
|
|
8c56146fef | |
|
|
d7846e5fbe | |
|
|
d18ea10e1f | |
|
|
e7798e8d15 | |
|
|
c1159a5448 | |
|
|
0dc16c5360 | |
|
|
39992e640b | |
|
|
103373f0db | |
|
|
d2fc4768fb | |
|
|
281334b7d9 | |
|
|
f76834fb4b | |
|
|
5be01ad19f | |
|
|
808dd623d6 | |
|
|
a00480ef07 | |
|
|
e14cd11417 | |
|
|
59699fc3bb | |
|
|
17568bd426 | |
|
|
1b3be7749a | |
|
|
fcd95905d8 | |
|
|
9ca151eebf | |
|
|
c52037d937 | |
|
|
68a4e8165b | |
|
|
a4a4fc77e0 | |
|
|
74855ceffc | |
|
|
420811cf2d | |
|
|
15724a01ca | |
|
|
75e399a9fb | |
|
|
8208f1aeaa | |
|
|
a19d910ef7 | |
|
|
0218c244d0 | |
|
|
0f2dd07152 | |
|
|
e1956d1b5a | |
|
|
085921d155 | |
|
|
75b3d183ec | |
|
|
6711778106 | |
|
|
1487355914 | |
|
|
9b4ada165c | |
|
|
35cf822849 | |
|
|
f5208a31d7 | |
|
|
f5022545a1 | |
|
|
08aea6d4f0 | |
|
|
d811afff37 | |
|
|
2e0eb6fae8 | |
|
|
6fca6886a0 | |
|
|
7b7579f8d4 | |
|
|
6f65413e4c | |
|
|
af284ea2a0 | |
|
|
e1aafea865 | |
|
|
7195618ae2 | |
|
|
82c7f622ee | |
|
|
4fcec9e7d5 | |
|
|
37661934e9 | |
|
|
1a6745b60b | |
|
|
c291359b76 | |
|
|
e2e68269b5 | |
|
|
909482474a | |
|
|
bc18d3e7a6 | |
|
|
cafdf5c7ef | |
|
|
a12f2e6c5c | |
|
|
196cfda526 | |
|
|
2bc77eaaac | |
|
|
0f311927be | |
|
|
c6ec37a8ab | |
|
|
03e1ce657f | |
|
|
033e3c7b66 | |
|
|
3c1272fd81 | |
|
|
08fcd8d501 | |
|
|
1c57d732b5 | |
|
|
27c4ceafd1 | |
|
|
d1e973e38c | |
|
|
8dfdb62e8a | |
|
|
5846b9f075 | |
|
|
1c0608e7f0 | |
|
|
2502f47028 | |
|
|
15eb261c70 | |
|
|
6c98e09f84 | |
|
|
a7baa022fb | |
|
|
6da3cf9d6d | |
|
|
3b235dcdfe | |
|
|
efd0bd3a2e | |
|
|
3cee54bab1 | |
|
|
528a2bf01d | |
|
|
4c948699ee | |
|
|
2f553d2316 | |
|
|
fd887d9893 | |
|
|
42c422b17d | |
|
|
c9a0d70658 | |
|
|
3317ddf93b | |
|
|
dc4297bfd5 | |
|
|
1a2b37bc00 | |
|
|
a256b40122 | |
|
|
2fee037428 | |
|
|
79a393155c | |
|
|
503a5a2e22 | |
|
|
07baf516e4 | |
|
|
8f23d225ba | |
|
|
2141d6789c | |
|
|
d03692a61b | |
|
|
21ba2d905a | |
|
|
2ec8274b7e | |
|
|
4bee9ff634 | |
|
|
4ddacfd622 | |
|
|
45b84bd0e1 | |
|
|
36793d80b3 | |
|
|
5307f7ed58 | |
|
|
f09099e23f | |
|
|
c9b90da7a9 | |
|
|
49439b612a | |
|
|
be44e7cc3f | |
|
|
9ca7a0244e | |
|
|
9036004d87 | |
|
|
64cebdc615 | |
|
|
1f02c756b5 | |
|
|
b9c74bb6f8 | |
|
|
7253d0d4dd | |
|
|
e19fe543bb | |
|
|
29eb5a7e49 | |
|
|
de083cda54 | |
|
|
c54e3a01d1 | |
|
|
04fec4dac9 | |
|
|
c844cf2844 | |
|
|
89b2a4a040 | |
|
|
2e5b4f2c28 | |
|
|
836ddcac38 | |
|
|
a4f7dbbacb | |
|
|
5fac3769cc | |
|
|
e329078e3e | |
|
|
a504f42fba | |
|
|
6654289904 | |
|
|
8d29caf5e5 | |
|
|
4d6f51ecac | |
|
|
b927fc4cf5 | |
|
|
1aa15920dd | |
|
|
a688b3d5dc | |
|
|
2c0233e81d | |
|
|
f169adb0e4 | |
|
|
709ef55984 | |
|
|
7434f84603 | |
|
|
4f0ab275d9 | |
|
|
7bbfe712bf | |
|
|
a0de38ece9 | |
|
|
e8121329bd | |
|
|
3eb9f73177 | |
|
|
f446be76f3 | |
|
|
7e2044a262 | |
|
|
f12f3bda9b | |
|
|
7822f531dd | |
|
|
de075a1040 | |
|
|
050c11f41f | |
|
|
641afe66f8 | |
|
|
cb904275ad | |
|
|
bc3cabff81 | |
|
|
f80ecb7ee0 | |
|
|
e84c5bebed | |
|
|
2eeaf34c14 | |
|
|
c49b1c310f | |
|
|
b99ec5c0a9 | |
|
|
357c914c14 | |
|
|
57b2439c3e | |
|
|
f5b02ec35b | |
|
|
aad75d5c8f | |
|
|
b5bbb6f8e5 | |
|
|
82047a7f14 | |
|
|
27f257cb87 | |
|
|
92fc0543c8 | |
|
|
4c64820020 | |
|
|
dfaa8568cc | |
|
|
70669f5764 | |
|
|
fa391322d7 | |
|
|
ab0fdc3831 | |
|
|
9816e6769a | |
|
|
875a15f889 | |
|
|
463f4663d3 | |
|
|
2c83d1f68f | |
|
|
8eeffd67b6 | |
|
|
635af96e3a | |
|
|
73d2ce93d6 | |
|
|
e7143ca139 | |
|
|
02bdefa411 | |
|
|
6c268945b5 | |
|
|
f1c84b3680 | |
|
|
93890fb94e | |
|
|
2581f56502 | |
|
|
d9caf88869 | |
|
|
c91119cad2 | |
|
|
7e76076702 | |
|
|
3c6f3c2469 | |
|
|
5308445c93 | |
|
|
eb266daa98 | |
|
|
0f87088618 | |
|
|
71e196e623 | |
|
|
f59599e991 | |
|
|
07f2052a23 | |
|
|
e283c38359 | |
|
|
313225c3d6 | |
|
|
c3979f77a5 | |
|
|
3a9d799f76 | |
|
|
ef817273bf | |
|
|
abb5a719a9 | |
|
|
49b3b73b10 | |
|
|
a11d86e3b7 | |
|
|
265179f6da | |
|
|
fc70fd6191 | |
|
|
d45474a3b0 | |
|
|
e673a670ac | |
|
|
50c41b58d1 | |
|
|
cdb6a97154 | |
|
|
7cf344e441 | |
|
|
6f81bf379e | |
|
|
b3d41bd4e3 | |
|
|
c67bed8b8a | |
|
|
84b46673d1 | |
|
|
9a6dc9387b | |
|
|
fb3cae236a | |
|
|
48155a7703 | |
|
|
dad0f0dd0d | |
|
|
30d89093f0 | |
|
|
b63566320c | |
|
|
8a61b7d7f4 | |
|
|
fa57ac9213 | |
|
|
bddfc518e1 | |
|
|
5b3cfa5751 | |
|
|
2fabbaa077 | |
|
|
ee984dd3e6 | |
|
|
4be850db09 | |
|
|
5a32061c1e | |
|
|
7da6113c8f | |
|
|
44a3cd923d | |
|
|
cb155ab8ae | |
|
|
fedbc69805 | |
|
|
e7775b3d93 | |
|
|
8ffd67753a | |
|
|
a9ebfebc17 | |
|
|
c6404c96c3 | |
|
|
0751a1b73d | |
|
|
a6f09ca00f | |
|
|
59e3e77e34 | |
|
|
840512b553 | |
|
|
1e27d82a52 | |
|
|
d975e56b80 | |
|
|
3120e0216a | |
|
|
e3f9a8c514 | |
|
|
01d9ff6b54 | |
|
|
245d0aaed7 | |
|
|
e4ed906551 | |
|
|
5d6e58361d | |
|
|
284c30c1f8 | |
|
|
0029e0b851 | |
|
|
b64d1e8e4d | |
|
|
56534400f8 | |
|
|
1307de48dc | |
|
|
56a4e1d2d9 | |
|
|
3c5bab88c0 | |
|
|
ae11c1233f | |
|
|
22073107ab | |
|
|
3236057389 | |
|
|
c3c7d05496 | |
|
|
1e6e9cae21 | |
|
|
b54e625841 | |
|
|
0d746c206c | |
|
|
bfcf9104c8 | |
|
|
50431e6a9a | |
|
|
c23b43e222 | |
|
|
5c4b20847b | |
|
|
452ef186d9 | |
|
|
7368ee38c0 | |
|
|
aaeaff86d9 | |
|
|
af681e6188 | |
|
|
060923d416 | |
|
|
1627587387 | |
|
|
f57b96b4bf | |
|
|
d05e77b271 | |
|
|
d018a5ecd0 | |
|
|
a410918e8e | |
|
|
2bb61d0cf8 | |
|
|
93f02f85be | |
|
|
4c5567cd6c | |
|
|
3d707712a1 | |
|
|
d2bb210af4 | |
|
|
4c00d73742 | |
|
|
adb57dd5a7 | |
|
|
0bb2b6916c | |
|
|
1c42649b11 |
|
|
@ -1,2 +0,0 @@
|
||||||
dist
|
|
||||||
demo
|
|
||||||
56
.eslintrc
56
.eslintrc
|
|
@ -1,56 +0,0 @@
|
||||||
{
|
|
||||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
|
||||||
"plugins": ["prettier"],
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2018,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"es6": true,
|
|
||||||
"browser": true,
|
|
||||||
"node": true,
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"block-scoped-var": 1,
|
|
||||||
"curly": 1,
|
|
||||||
"eqeqeq": 1,
|
|
||||||
"no-global-assign": 1,
|
|
||||||
"no-implicit-globals": 1,
|
|
||||||
"no-labels": 1,
|
|
||||||
"no-multi-str": 1,
|
|
||||||
"comma-spacing": 1,
|
|
||||||
"comma-style": 1,
|
|
||||||
"func-call-spacing": 1,
|
|
||||||
"keyword-spacing": 1,
|
|
||||||
"linebreak-style": 1,
|
|
||||||
"no-multiple-empty-lines": 1,
|
|
||||||
"space-infix-ops": 1,
|
|
||||||
"arrow-spacing": 1,
|
|
||||||
"no-var": 1,
|
|
||||||
"prefer-const": 1,
|
|
||||||
"no-unsafe-negation": 1,
|
|
||||||
"array-callback-return": 1,
|
|
||||||
"dot-notation": 1,
|
|
||||||
"no-eval": 1,
|
|
||||||
"no-extend-native": 1,
|
|
||||||
"no-extra-label": 1,
|
|
||||||
"semi": 1,
|
|
||||||
"space-before-blocks": 1,
|
|
||||||
"space-in-parens": 1,
|
|
||||||
"space-unary-ops": 1,
|
|
||||||
"spaced-comment": 1,
|
|
||||||
"arrow-body-style": 1,
|
|
||||||
"arrow-parens": 1,
|
|
||||||
"no-restricted-imports": 1,
|
|
||||||
"no-duplicate-imports": 1,
|
|
||||||
"no-useless-computed-key": 1,
|
|
||||||
"no-useless-rename": 1,
|
|
||||||
"rest-spread-spacing": 1,
|
|
||||||
"no-trailing-spaces": 1,
|
|
||||||
"no-control-regex": 0,
|
|
||||||
"prettier/prettier": 0,
|
|
||||||
"no-await-in-loop": 1,
|
|
||||||
"require-atomic-updates": 0,
|
|
||||||
"no-prototype-builtins": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
pnpm exec lint-staged
|
||||||
64
README.md
64
README.md
|
|
@ -8,13 +8,11 @@
|
||||||
[](https://www.npmjs.com/package/dplayer)
|
[](https://www.npmjs.com/package/dplayer)
|
||||||
[](https://github.com/MoePlayer/DPlayer/blob/master/LICENSE)
|
[](https://github.com/MoePlayer/DPlayer/blob/master/LICENSE)
|
||||||
[](https://www.npmjs.com/package/dplayer)
|
[](https://www.npmjs.com/package/dplayer)
|
||||||
[](https://github.com/MoePlayer/DPlayer/tree/master/dist)
|
[](https://www.jsdelivr.com/package/npm/dplayer)
|
||||||
[](https://travis-ci.org/MoePlayer/DPlayer)
|
|
||||||
[](https://david-dm.org/MoePlayer/DPlayer#info=devDependencies)
|
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
DPlayer is a lovely HTML5 danmaku video player to help people build video and danmaku easily.
|
DPlayer is a lovely HTML5 danmaku video player to help people build video and danmaku easily.
|
||||||
|
|
||||||
|
|
@ -40,40 +38,24 @@ DPlayer is a lovely HTML5 danmaku video player to help people build video and da
|
||||||
|
|
||||||
Using DPlayer on your project? [Let me know!](https://github.com/DIYgod/DPlayer/issues/31)
|
Using DPlayer on your project? [Let me know!](https://github.com/DIYgod/DPlayer/issues/31)
|
||||||
|
|
||||||
**[Docs](http://dplayer.js.org)**
|
**[Docs](https://dplayer.diygod.dev/)**
|
||||||
|
|
||||||
**[中文文档](http://dplayer.js.org/#/zh-Hans/)**
|
**[中文文档](https://dplayer.diygod.dev/zh/)**
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
||||||
### Special Sponsors
|
### Sponsors
|
||||||
|
|
||||||
<div>
|
|
||||||
<a href="https://www.cdnbye.com" target="_blank">
|
|
||||||
<img height="60px" src="https://cdnbye.oss-cn-beijing.aliyuncs.com/pic/cdnbye-dp.jpeg">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
||||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
| [极酷社](https://www.acg.app) |
|
|
||||||
| :---------------------------: |
|
|
||||||
|
|
||||||
|
|
||||||
### Contributors
|
### Contributors
|
||||||
|
|
||||||
<a href="https://github.com/MoePlayer/DPlayer/graphs/contributors"><img src="https://opencollective.com/DPlayer/contributors.svg?width=890" /></a>
|
<a href="https://github.com/MoePlayer/DPlayer/graphs/contributors"><img src="https://opencollective.com/DPlayer/contributors.svg?width=890" /></a>
|
||||||
|
|
||||||
## Join the Discussion
|
|
||||||
|
|
||||||
- [Telegram Group](https://t.me/adplayer)
|
|
||||||
|
|
||||||
## Related Projects
|
## Related Projects
|
||||||
|
|
||||||
Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
||||||
|
|
@ -100,11 +82,13 @@ Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlay
|
||||||
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
||||||
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
||||||
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
||||||
|
- [rc-dplayer](https://github.com/tianfeng98/rc-dplayer): React
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
|
|
||||||
- [DPlayer-Lite](https://github.com/kn007/DPlayer-Lite): lite version
|
- [DPlayer-Lite](https://github.com/kn007/DPlayer-Lite): lite version
|
||||||
- [hlsjs-p2p-engine](https://github.com/cdnbye/hlsjs-p2p-engine)
|
- [hlsjs-p2p-engine](https://github.com/cdnbye/hlsjs-p2p-engine): Let your viewers become your unlimitedly scalable CDN
|
||||||
|
- [CBPlayer](https://github.com/cdnbye/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!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
||||||
|
|
||||||
## Who use DPlayer?
|
## Who use DPlayer?
|
||||||
|
|
@ -119,26 +103,34 @@ Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlay
|
||||||
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
||||||
- [Cloudreve](https://github.com/HFO4/Cloudreve): 基于 ThinkPHP 构建的网盘系统
|
- [Cloudreve](https://github.com/HFO4/Cloudreve): 基于 ThinkPHP 构建的网盘系统
|
||||||
- [oneindex](https://github.com/donwa/oneindex): Onedrive Directory Index
|
- [oneindex](https://github.com/donwa/oneindex): Onedrive Directory Index
|
||||||
|
- [arozos](https://github.com/tobychui/arozos): General purposed Web Desktop Operating Platform / OS for Raspberry Pis
|
||||||
|
- [新东方云教室](https://roombox.xdf.cn/)
|
||||||
|
- [BBHouse](https://github.com/endcloud/bbhouse-tauri): A Bilibili Cross-Platform Desktop Client Powered By Tauri
|
||||||
|
- [Tampermonkey 阿里云盘](https://greasyfork.org/zh-CN/scripts/425955-%E9%98%BF%E9%87%8C%E4%BA%91%E7%9B%98)
|
||||||
|
- [arozos](https://github.com/tobychui/arozos)
|
||||||
|
- [GBCLStudio/fof-upload-qcloud](https://github.com/GBCLStudio/FoF-Upload-Qcloud)
|
||||||
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
||||||
|
|
||||||
## Donate
|
## 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.
|
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.
|
||||||
|
|
||||||
## One-time Donations
|
You can support DPlayer via donations.
|
||||||
|
|
||||||
We accept donations through these channels:
|
### Recurring Donation
|
||||||
|
|
||||||
|
- Become a Sponser on [GitHub](https://github.com/sponsors/DIYgod)
|
||||||
|
- Become a Sponser on [Patreon](https://www.patreon.com/DIYgod)
|
||||||
|
- Become a Sponser on [爱发电](https://afdian.net/@diygod)
|
||||||
|
- Contact us directly: i@diygod.me
|
||||||
|
|
||||||
|
### One-time Donation
|
||||||
|
|
||||||
|
We accept donations via the following ways:
|
||||||
|
|
||||||
|
- [WeChat Pay](https://diygod.me/images/wx.jpg)
|
||||||
|
- [Alipay](https://diygod.me/images/zfb.jpg)
|
||||||
- [Paypal](https://www.paypal.me/DIYgod)
|
- [Paypal](https://www.paypal.me/DIYgod)
|
||||||
- [WeChat Pay](https://i.imgur.com/aq6PtWa.png)
|
|
||||||
- [Alipay](https://i.imgur.com/wv1Pj2k.png)
|
|
||||||
|
|
||||||
## Recurring Pledges
|
|
||||||
|
|
||||||
Recurring pledges come with exclusive perks, e.g. enabling faster GitHub response, having your name or your company logo listed in the DPlayer GitHub repository and this website.
|
|
||||||
|
|
||||||
- Become a backer or sponsor via [Patreon](https://www.patreon.com/DIYgod)
|
|
||||||
- E-mail us: i#html.love
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
|
|
||||||
28
demo/demo.js
28
demo/demo.js
|
|
@ -65,7 +65,23 @@ function initPlayers() {
|
||||||
thumbnails: 'https://i.loli.net/2019/06/06/5cf8c5d9cec8510758.jpg'
|
thumbnails: 'https://i.loli.net/2019/06/06/5cf8c5d9cec8510758.jpg'
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
url: 'https://s-sh-17-dplayercdn.oss.dogecdn.com/hikarunara.vtt'
|
url: [
|
||||||
|
{
|
||||||
|
url: 'https://s-sh-17-dplayercdn.oss.dogecdn.com/hikarunara.vtt',
|
||||||
|
lang: 'zh-cn',
|
||||||
|
name: '光',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'https://gist.githubusercontent.com/samdutton/ca37f3adaf4e23679957b8083e061177/raw/e19399fbccbc069a2af4266e5120ae6bad62699a/sample.vtt',
|
||||||
|
lang: 'en-us',
|
||||||
|
name: 'github',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultSubtitle: 7,
|
||||||
|
type: 'webvtt',
|
||||||
|
fontSize: '25px',
|
||||||
|
bottom: '10%',
|
||||||
|
color: '#b7daff'
|
||||||
},
|
},
|
||||||
danmaku: {
|
danmaku: {
|
||||||
id: '9E2E3368B56CDBB4',
|
id: '9E2E3368B56CDBB4',
|
||||||
|
|
@ -83,10 +99,12 @@ function initPlayers() {
|
||||||
loop: true,
|
loop: true,
|
||||||
screenshot: true,
|
screenshot: true,
|
||||||
airplay: true,
|
airplay: true,
|
||||||
|
chromecast: true,
|
||||||
hotkey: true,
|
hotkey: true,
|
||||||
logo: 'https://i.loli.net/2019/06/06/5cf8c5d94521136430.png',
|
logo: 'https://i.loli.net/2019/06/06/5cf8c5d94521136430.png',
|
||||||
volume: 0.2,
|
volume: 0.2,
|
||||||
mutex: true,
|
mutex: true,
|
||||||
|
lang: 'zh-cn',
|
||||||
video: {
|
video: {
|
||||||
url: 'https://api.dogecloud.com/player/get.mp4?vcode=5ac682e6f8231991&userId=17&ext=.mp4',
|
url: 'https://api.dogecloud.com/player/get.mp4?vcode=5ac682e6f8231991&userId=17&ext=.mp4',
|
||||||
pic: 'https://i.loli.net/2019/06/06/5cf8c5d9c57b510947.png',
|
pic: 'https://i.loli.net/2019/06/06/5cf8c5d9c57b510947.png',
|
||||||
|
|
@ -103,11 +121,13 @@ function initPlayers() {
|
||||||
danmaku: {
|
danmaku: {
|
||||||
id: '9E2E3368B56CDBB4',
|
id: '9E2E3368B56CDBB4',
|
||||||
api: 'https://api.prprpr.me/dplayer/',
|
api: 'https://api.prprpr.me/dplayer/',
|
||||||
|
addition: ['https://s-sh-17-dplayercdn.oss.dogecdn.com/1678963.json'],
|
||||||
token: 'tokendemo',
|
token: 'tokendemo',
|
||||||
maximum: 3000,
|
maximum: 3000,
|
||||||
user: 'DIYgod',
|
user: 'DIYgod',
|
||||||
bottom: '15%',
|
bottom: '15%',
|
||||||
unlimited: true
|
unlimited: true,
|
||||||
|
speedRate: 0.5,
|
||||||
},
|
},
|
||||||
contextmenu: [
|
contextmenu: [
|
||||||
{
|
{
|
||||||
|
|
@ -137,7 +157,7 @@ function initPlayers() {
|
||||||
const eventsEle = document.getElementById('events');
|
const eventsEle = document.getElementById('events');
|
||||||
for (let i = 0; i < events.length; i++) {
|
for (let i = 0; i < events.length; i++) {
|
||||||
dp2.on(events[i], (info) => {
|
dp2.on(events[i], (info) => {
|
||||||
eventsEle.innerHTML += '<p>Event: ' + events[i] + '</p>';
|
eventsEle.innerHTML += `<p>Event: ${events[i]} ${info?`Data: <span>${JSON.stringify(info)}</span>`:''}</p>`;
|
||||||
eventsEle.scrollTop = eventsEle.scrollHeight;
|
eventsEle.scrollTop = eventsEle.scrollHeight;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -244,7 +264,7 @@ function clearPlayers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchDPlayer() {
|
function switchDPlayer() {
|
||||||
if (dp2.option.danmaku.id !== '5rGf5Y2X55qu6Z2p') {
|
if (dp2.options.danmaku.id !== '5rGf5Y2X55qu6Z2p') {
|
||||||
dp2.switchVideo({
|
dp2.switchVideo({
|
||||||
url: 'http://static.smartisanos.cn/common/video/t1-ui.mp4',
|
url: 'http://static.smartisanos.cn/common/video/t1-ui.mp4',
|
||||||
pic: 'http://static.smartisanos.cn/pr/img/video/video_03_cc87ce5bdb.jpg',
|
pic: 'http://static.smartisanos.cn/pr/img/video/video_03_cc87ce5bdb.jpg',
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -71,12 +71,16 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
load: function () {
|
load: function () {
|
||||||
this.options.container = this.$refs.dplayer;
|
this.options.container = this.$refs.dplayer;
|
||||||
this.dplayer = new window.DPlayer(this.options);
|
setTimeout(() => {
|
||||||
|
this.dplayer = new window.DPlayer(this.options);
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
if (this.immediate) {
|
if (this.immediate) {
|
||||||
this.dplayer = new window.DPlayer(this.options);
|
setTimeout(() => {
|
||||||
|
this.dplayer = new window.DPlayer(this.options);
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy: function () {
|
beforeDestroy: function () {
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,10 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: {
|
plugins: {
|
||||||
'@vuepress/google-analytics': {
|
|
||||||
ga: 'UA-48084758-9',
|
|
||||||
},
|
|
||||||
'@vuepress/pwa': {
|
|
||||||
serviceWorker: true,
|
|
||||||
updatePopup: {
|
|
||||||
'/zh/': {
|
|
||||||
message: '发现新内容可用',
|
|
||||||
buttonText: '刷新',
|
|
||||||
},
|
|
||||||
'/': {
|
|
||||||
message: 'New content is available',
|
|
||||||
buttonText: 'Refresh',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'@vuepress/back-to-top': true,
|
'@vuepress/back-to-top': true,
|
||||||
|
umami: {
|
||||||
|
trackerUrl: 'https://umami.diygod.dev',
|
||||||
|
siteId: 'f3b469a2-8054-4bbb-8873-4035761aa4e3',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
locales: {
|
locales: {
|
||||||
'/zh/': {
|
'/zh/': {
|
||||||
|
|
@ -38,10 +26,11 @@ module.exports = {
|
||||||
['script', { src: 'https://cdn.jsdelivr.net/webtorrent/latest/webtorrent.min.js' }],
|
['script', { src: 'https://cdn.jsdelivr.net/webtorrent/latest/webtorrent.min.js' }],
|
||||||
['script', { src: 'https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js' }],
|
['script', { src: 'https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js' }],
|
||||||
],
|
],
|
||||||
|
theme: 'vuepress-theme-dplayer',
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
repo: 'MoePlayer/DPlayer',
|
repo: 'MoePlayer/DPlayer',
|
||||||
editLinks: true,
|
editLinks: true,
|
||||||
docsDir: 'docs',
|
docsDir: '.',
|
||||||
locales: {
|
locales: {
|
||||||
'/zh/': {
|
'/zh/': {
|
||||||
lang: 'zh-CN',
|
lang: 'zh-CN',
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
dplayer.js.org
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'CarbonAds',
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
'$route' (to, from) {
|
||||||
|
if (
|
||||||
|
to.path !== from.path
|
||||||
|
// Only reload if the ad has been loaded
|
||||||
|
// otherwise it's possible that the script is appended but
|
||||||
|
// the ads are not loaded yet. This would result in duplicated ads.
|
||||||
|
&& this.$el.querySelector('#carbonads')
|
||||||
|
) {
|
||||||
|
this.$el.innerHTML = ''
|
||||||
|
this.load()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
this.load()
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
load () {
|
||||||
|
const s = document.createElement('script')
|
||||||
|
s.id = '_carbonads_js'
|
||||||
|
s.src = `//cdn.carbonads.com/carbon.js?serve=CEAI6277&placement=dplayerjsorg`
|
||||||
|
this.$el.appendChild(s)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render (h) {
|
||||||
|
return h('div', { class: 'carbon-ads' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.carbon-ads
|
||||||
|
min-height 102px
|
||||||
|
padding 1.5rem 1.5rem 0
|
||||||
|
margin-bottom -0.5rem
|
||||||
|
font-size 0.75rem
|
||||||
|
a
|
||||||
|
color #444
|
||||||
|
font-weight normal
|
||||||
|
display inline
|
||||||
|
.carbon-img
|
||||||
|
float left
|
||||||
|
margin-right 1rem
|
||||||
|
border 1px solid $borderColor
|
||||||
|
img
|
||||||
|
display block
|
||||||
|
.carbon-poweredby
|
||||||
|
color #999
|
||||||
|
display block
|
||||||
|
margin-top 0.5em
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.carbon-ads
|
||||||
|
.carbon-img img
|
||||||
|
width 100px
|
||||||
|
height 77px
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
extend: '@vuepress/theme-default',
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<ParentLayout>
|
||||||
|
<template #sidebar-top>
|
||||||
|
<CarbonAds />
|
||||||
|
</template>
|
||||||
|
</ParentLayout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ParentLayout from '@parent-theme/layouts/Layout.vue'
|
||||||
|
import CarbonAds from '@theme/components/CarbonAds.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Layout',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
ParentLayout,
|
||||||
|
CarbonAds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "vuepress-theme-dplayer",
|
||||||
|
"main": "index.js"
|
||||||
|
}
|
||||||
|
|
@ -8,10 +8,6 @@ Let's make DPlayer better, feel free to submit yours in [`Let me know!`](https:/
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
|
|
||||||
### Joining the Discussion
|
|
||||||
|
|
||||||
- [Telegram Group](https://t.me/adplayer)
|
|
||||||
|
|
||||||
### Creating issue
|
### Creating issue
|
||||||
|
|
||||||
- [MoePlayer/DPlayer/issues](https://github.com/MoePlayer/DPlayer/issues)
|
- [MoePlayer/DPlayer/issues](https://github.com/MoePlayer/DPlayer/issues)
|
||||||
|
|
@ -40,6 +36,7 @@ Let's make DPlayer better, feel free to submit yours in [`Let me know!`](https:/
|
||||||
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
||||||
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
||||||
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
||||||
|
- [rc-dplayer](https://github.com/tianfeng98/rc-dplayer): React
|
||||||
|
|
||||||
### Other
|
### Other
|
||||||
|
|
||||||
|
|
@ -57,6 +54,13 @@ Let's make DPlayer better, feel free to submit yours in [`Let me know!`](https:/
|
||||||
- [纸飞机南航青年网络社区](http://my.nuaa.edu.cn/video-video.html): 南京航空航天大学门户网站
|
- [纸飞机南航青年网络社区](http://my.nuaa.edu.cn/video-video.html): 南京航空航天大学门户网站
|
||||||
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
||||||
- [Cloudreve](https://github.com/HFO4/Cloudreve): 基于 ThinkPHP 构建的网盘系统
|
- [Cloudreve](https://github.com/HFO4/Cloudreve): 基于 ThinkPHP 构建的网盘系统
|
||||||
|
- [arozos](https://github.com/tobychui/arozos): General purposed Web Desktop Operating Platform / OS for Raspberry Pis
|
||||||
|
- [新东方云教室](https://roombox.xdf.cn/)
|
||||||
|
- [BBHouse](https://github.com/endcloud/bbhouse-tauri): A Bilibili Cross-Platform Desktop Client Powered By Tauri
|
||||||
|
- [Tampermonkey 阿里云盘](https://greasyfork.org/zh-CN/scripts/425955-%E9%98%BF%E9%87%8C%E4%BA%91%E7%9B%98)
|
||||||
|
- [arozos](https://github.com/tobychui/arozos)
|
||||||
|
- [GBCLStudio/fof-upload-qcloud](https://github.com/GBCLStudio/FoF-Upload-Qcloud)
|
||||||
|
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,28 +14,16 @@ sidebar: auto
|
||||||
|
|
||||||
## Special Thanks
|
## Special Thanks
|
||||||
|
|
||||||
### Special Sponsors
|
### Sponsors
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a href="https://www.cdnbye.com" target="_blank">
|
|
||||||
<img height="60px" src="https://cdnbye.oss-cn-beijing.aliyuncs.com/pic/cdnbye-dp.jpeg">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
||||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
| [极酷社](https://www.acg.app) |
|
|
||||||
| :---------------------------: |
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Using npm:
|
Using npm:
|
||||||
|
|
@ -103,13 +91,15 @@ You can custom your player instance by those options
|
||||||
| loop | false | video loop |
|
| loop | false | video loop |
|
||||||
| lang | navigator.language.toLowerCase() | values: 'en', 'zh-cn', 'zh-tw' |
|
| lang | navigator.language.toLowerCase() | values: 'en', 'zh-cn', 'zh-tw' |
|
||||||
| screenshot | false | enable screenshot, if true, video and video poster must enable Cross-Origin |
|
| screenshot | false | enable screenshot, if true, video and video poster must enable Cross-Origin |
|
||||||
| airplay | true | enable airplay in Safari |
|
| airplay | false | enable airplay in Safari |
|
||||||
|
| chromecast | false | enable Chromecast |
|
||||||
| hotkey | true | enable hotkey, support FF, FR, volume control, play & pause |
|
| hotkey | true | enable hotkey, support FF, FR, volume control, play & pause |
|
||||||
| preload | 'auto' | values: 'none', 'metadata', 'auto' |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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](#live) |
|
| apiBackend | - | getting and sending danmaku in your way, see [#live](#live) |
|
||||||
|
| preventClickToggle | false | prevent toggle video play/pause status when click player |
|
||||||
| video | - | video info |
|
| video | - | video info |
|
||||||
| video.quality | - | see [#Quality switching](#quality-switching) |
|
| video.quality | - | see [#Quality switching](#quality-switching) |
|
||||||
| video.defaultQuality | - | see [#Quality switching](#quality-switching) |
|
| video.defaultQuality | - | see [#Quality switching](#quality-switching) |
|
||||||
|
|
@ -133,6 +123,7 @@ You can custom your player instance by those options
|
||||||
| danmaku.user | 'DIYgod' | danmaku user name |
|
| 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.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.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 |
|
| contextmenu | [] | custom contextmenu |
|
||||||
| highlight | [] | custom time markers upon progress bar |
|
| 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 |
|
| mutex | true | prevent to play multiple player at the same time, pause other players when this player start play |
|
||||||
|
|
@ -172,6 +163,7 @@ const dp = new DPlayer({
|
||||||
user: 'DIYgod',
|
user: 'DIYgod',
|
||||||
bottom: '15%',
|
bottom: '15%',
|
||||||
unlimited: true,
|
unlimited: true,
|
||||||
|
speedRate: 0.5,
|
||||||
},
|
},
|
||||||
contextmenu: [
|
contextmenu: [
|
||||||
{
|
{
|
||||||
|
|
@ -212,7 +204,7 @@ const dp = new DPlayer({
|
||||||
|
|
||||||
- `dp.toggle()`: toggle between play and pause
|
- `dp.toggle()`: toggle between play and pause
|
||||||
|
|
||||||
- `dp.on(event: string, handler: function)`: bind video and player events, [see more details](http://dplayer.js.org/#/home?id=event-binding)
|
- `dp.on(event: string, handler: function)`: bind video and player events, [see more details](https://dplayer.diygod.dev/guide.html#event-binding)
|
||||||
|
|
||||||
- `dp.switchVideo(video, danmaku)`: switch to a new video
|
- `dp.switchVideo(video, danmaku)`: switch to a new video
|
||||||
|
|
||||||
|
|
@ -420,15 +412,56 @@ const dp = new DPlayer({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When using `customType` ([Work with other MSE library](#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.
|
||||||
|
|
||||||
|
```js
|
||||||
|
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
|
||||||
|
|
||||||
### Danmaku API
|
### Danmaku API
|
||||||
|
|
||||||
`danmaku.api`
|
`danmaku.api`
|
||||||
|
|
||||||
**Ready-made API**
|
<!-- **Ready-made API**
|
||||||
|
|
||||||
url: https://api.prprpr.me/dplayer/
|
url: https://api.prprpr.me/dplayer/ -->
|
||||||
|
|
||||||
Daily backup data: [DPlayer-data](https://github.com/DIYgod/DPlayer-data)
|
Daily backup data: [DPlayer-data](https://github.com/DIYgod/DPlayer-data)
|
||||||
|
|
||||||
|
|
@ -703,22 +736,32 @@ DPlayer can work with any MSE library via `customType` option.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div id="dplayer"></div>
|
<div id="dplayer"></div>
|
||||||
<script src="pearplayer.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/cdnbye@latest"></script>
|
||||||
<script src="DPlayer.min.js"></script>
|
<script src="DPlayer.min.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var type = 'normal';
|
||||||
|
if (Hls.isSupported() && Hls.WEBRTC_SUPPORT) {
|
||||||
|
type = 'customHls';
|
||||||
|
}
|
||||||
const dp = new DPlayer({
|
const dp = new DPlayer({
|
||||||
container: document.getElementById('dplayer'),
|
container: document.getElementById('dplayer'),
|
||||||
video: {
|
video: {
|
||||||
url: 'https://qq.webrtc.win/tv/Pear-Demo-Yosemite_National_Park.mp4',
|
url: 'demo.m3u8',
|
||||||
type: 'pearplayer',
|
type: type,
|
||||||
customType: {
|
customType: {
|
||||||
pearplayer: function (video, player) {
|
customHls: function (video, player) {
|
||||||
new PearPlayer(video, {
|
const hls = new Hls({
|
||||||
src: video.src,
|
debug: false,
|
||||||
autoplay: player.options.autoplay,
|
// 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);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -747,11 +790,11 @@ const dp = new DPlayer({
|
||||||
apiBackend: {
|
apiBackend: {
|
||||||
read: function (options) {
|
read: function (options) {
|
||||||
console.log('Pretend to connect WebSocket');
|
console.log('Pretend to connect WebSocket');
|
||||||
callback();
|
options.success([]);
|
||||||
},
|
},
|
||||||
send: function (options) {
|
send: function (options) {
|
||||||
console.log('Pretend to send danmaku via WebSocket', options.data);
|
console.log('Pretend to send danmaku via WebSocket', options.data);
|
||||||
callback();
|
options.success();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
video: {
|
video: {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "docs",
|
||||||
|
"scripts": {
|
||||||
|
"docs:dev": "vuepress dev",
|
||||||
|
"docs:build": "vuepress build"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@vuepress/plugin-back-to-top": "^1.9.10",
|
||||||
|
"@vuepress/plugin-google-analytics": "^1.9.10",
|
||||||
|
"vuepress": "^1.9.10",
|
||||||
|
"vuepress-plugin-umami": "^0.0.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -10,44 +10,30 @@ If you run a business and are using DPlayer in a revenue-generating product, it
|
||||||
|
|
||||||
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 :)
|
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 development via the following methods:
|
You can support DPlayer via donations.
|
||||||
|
|
||||||
## One-time Donations
|
### Recurring Donation
|
||||||
|
|
||||||
We accept donations through these channels:
|
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](https://github.com/sponsors/DIYgod)
|
||||||
|
- Become a Sponser on [Patreon](https://www.patreon.com/DIYgod)
|
||||||
|
- Become a Sponser on [爱发电](https://afdian.net/@diygod)
|
||||||
|
- Contact us directly: i@diygod.me
|
||||||
|
|
||||||
|
### One-time Donation
|
||||||
|
|
||||||
|
We accept donations via the following ways:
|
||||||
|
|
||||||
|
- [WeChat Pay](https://diygod.me/images/wx.jpg)
|
||||||
|
- [Alipay](https://diygod.me/images/zfb.jpg)
|
||||||
- [Paypal](https://www.paypal.me/DIYgod)
|
- [Paypal](https://www.paypal.me/DIYgod)
|
||||||
- [WeChat Pay](https://i.imgur.com/aq6PtWa.png)
|
|
||||||
- [Alipay](https://i.imgur.com/wv1Pj2k.png)
|
|
||||||
|
|
||||||
## Recurring Pledges
|
## Sponsors
|
||||||
|
|
||||||
Recurring pledges come with exclusive perks, e.g. having your name or your company logo listed in the DPlayer GitHub repository and this website.
|
|
||||||
|
|
||||||
- Become a Backer or a Sponser on [Patreon](https://www.patreon.com/DIYgod)
|
|
||||||
- E-mail us: i#diygod.me
|
|
||||||
|
|
||||||
## Current Premium Sponsors
|
|
||||||
|
|
||||||
### Special Sponsors
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a href="https://www.cdnbye.com" target="_blank">
|
|
||||||
<img height="60px" src="https://cdnbye.oss-cn-beijing.aliyuncs.com/pic/cdnbye-dp.jpeg">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
||||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
<img width="222px" src="hhttps://player.dogecloud.com/img/logo_with_product3.png">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
| [极酷社](https://www.acg.app) |
|
|
||||||
| :---------------------------: |
|
|
||||||
|
|
||||||
|
|
||||||
## DPlayer contributors
|
## DPlayer contributors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
home: true
|
home: true
|
||||||
actionText: Get Started →
|
actionText: Get Started →
|
||||||
actionLink: /guide/
|
actionLink: /zh/guide/
|
||||||
footer: MIT Licensed | Made with love by DIYgod
|
footer: MIT Licensed | Made with love by DIYgod
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -9,4 +9,4 @@ footer: MIT Licensed | Made with love by DIYgod
|
||||||
<DPlayer :immediate="true"></DPlayer>
|
<DPlayer :immediate="true"></DPlayer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hero custom"><p class="action"><router-link to="/guide/" class="nav-link action-button">快速上手 →</router-link></p></div>
|
<div class="hero custom"><p class="action"><router-link to="/zh/guide/" class="nav-link action-button">快速上手 →</router-link></p></div>
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,6 @@ sidebar: auto
|
||||||
|
|
||||||
## 帮助
|
## 帮助
|
||||||
|
|
||||||
### 参与讨论
|
|
||||||
|
|
||||||
- [Telegram 群](https://t.me/adplayer)
|
|
||||||
|
|
||||||
### 提交 issue
|
### 提交 issue
|
||||||
|
|
||||||
- [MoePlayer/DPlayer/issues](https://github.com/MoePlayer/DPlayer/issues)
|
- [MoePlayer/DPlayer/issues](https://github.com/MoePlayer/DPlayer/issues)
|
||||||
|
|
@ -40,6 +36,7 @@ sidebar: auto
|
||||||
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
||||||
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
||||||
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
||||||
|
- [rc-dplayer](https://github.com/tianfeng98/rc-dplayer): React
|
||||||
|
|
||||||
### 其他
|
### 其他
|
||||||
|
|
||||||
|
|
@ -57,3 +54,10 @@ sidebar: auto
|
||||||
- [纸飞机南航青年网络社区](http://my.nuaa.edu.cn/video-video.html): 南京航空航天大学门户网站
|
- [纸飞机南航青年网络社区](http://my.nuaa.edu.cn/video-video.html): 南京航空航天大学门户网站
|
||||||
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
||||||
- [Cloudreve](https://github.com/HFO4/Cloudreve): 基于 ThinkPHP 构建的网盘系统
|
- [Cloudreve](https://github.com/HFO4/Cloudreve): 基于 ThinkPHP 构建的网盘系统
|
||||||
|
- [arozos](https://github.com/tobychui/arozos): General purposed Web Desktop Operating Platform / OS for Raspberry Pis
|
||||||
|
- [新东方云教室](https://roombox.xdf.cn/)
|
||||||
|
- [BBHouse](https://github.com/endcloud/bbhouse-tauri): A Bilibili Cross-Platform Desktop Client Powered By Tauri
|
||||||
|
- [Tampermonkey 阿里云盘](https://greasyfork.org/zh-CN/scripts/425955-%E9%98%BF%E9%87%8C%E4%BA%91%E7%9B%98)
|
||||||
|
- [arozos](https://github.com/tobychui/arozos)
|
||||||
|
- [GBCLStudio/fof-upload-qcloud](https://github.com/GBCLStudio/FoF-Upload-Qcloud)
|
||||||
|
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
||||||
|
|
|
||||||
103
docs/zh/guide.md
103
docs/zh/guide.md
|
|
@ -14,26 +14,14 @@ sidebar: auto
|
||||||
|
|
||||||
## Special Thanks
|
## Special Thanks
|
||||||
|
|
||||||
### Special Sponsors
|
### Sponsors
|
||||||
|
|
||||||
<div>
|
|
||||||
<a href="https://www.cdnbye.com" target="_blank">
|
|
||||||
<img height="60px" src="https://cdnbye.oss-cn-beijing.aliyuncs.com/pic/cdnbye-dp.jpeg">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
||||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
| [极酷社](https://www.acg.app) |
|
|
||||||
| :---------------------------: |
|
|
||||||
|
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
使用 npm:
|
使用 npm:
|
||||||
|
|
@ -94,12 +82,14 @@ DPlayer 有丰富的参数可以自定义你的播放器实例
|
||||||
| lang | navigator.language.toLowerCase() | 可选值: 'en', 'zh-cn', 'zh-tw' |
|
| lang | navigator.language.toLowerCase() | 可选值: 'en', 'zh-cn', 'zh-tw' |
|
||||||
| screenshot | false | 开启截图,如果开启,视频和视频封面需要允许跨域 |
|
| screenshot | false | 开启截图,如果开启,视频和视频封面需要允许跨域 |
|
||||||
| hotkey | true | 开启热键,支持快进、快退、音量控制、播放暂停 |
|
| hotkey | true | 开启热键,支持快进、快退、音量控制、播放暂停 |
|
||||||
| airplay | true | 在 Safari 中开启 AirPlay |
|
| airplay | false | 在 Safari 中开启 AirPlay |
|
||||||
|
| chromecast | false | 启用 Chromecast |
|
||||||
| preload | 'auto' | 视频预加载,可选值: 'none', 'metadata', 'auto' |
|
| preload | 'auto' | 视频预加载,可选值: 'none', 'metadata', 'auto' |
|
||||||
| volume | 0.7 | 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 |
|
| volume | 0.7 | 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 |
|
||||||
| playbackSpeed | [0.5, 0.75, 1, 1.25, 1.5, 2] | 可选的播放速率,可以设置成自定义的数组 |
|
| playbackSpeed | [0.5, 0.75, 1, 1.25, 1.5, 2] | 可选的播放速率,可以设置成自定义的数组 |
|
||||||
| logo | - | 在左上角展示一个 logo,你可以通过 CSS 调整它的大小和位置 |
|
| logo | - | 在左上角展示一个 logo,你可以通过 CSS 调整它的大小和位置 |
|
||||||
| apiBackend | - | 自定义获取和发送弹幕行为,见[#直播](#直播) |
|
| apiBackend | - | 自定义获取和发送弹幕行为,见[#直播](#直播) |
|
||||||
|
| preventClickToggle | false | 阻止点击播放器时候自动切换播放/暂停 |
|
||||||
| video | - | 视频信息 |
|
| video | - | 视频信息 |
|
||||||
| video.quality | - | 见[#清晰度切换](#清晰度切换) |
|
| video.quality | - | 见[#清晰度切换](#清晰度切换) |
|
||||||
| video.defaultQuality | - | 见[#清晰度切换](#清晰度切换) |
|
| video.defaultQuality | - | 见[#清晰度切换](#清晰度切换) |
|
||||||
|
|
@ -123,6 +113,7 @@ DPlayer 有丰富的参数可以自定义你的播放器实例
|
||||||
| danmaku.user | 'DIYgod' | 弹幕用户名 |
|
| danmaku.user | 'DIYgod' | 弹幕用户名 |
|
||||||
| danmaku.bottom | - | 弹幕距离播放器底部的距离,防止遮挡字幕,取值形如: '10px' '10%' |
|
| danmaku.bottom | - | 弹幕距离播放器底部的距离,防止遮挡字幕,取值形如: '10px' '10%' |
|
||||||
| danmaku.unlimited | false | 海量弹幕模式,即使重叠也展示全部弹幕,请注意播放器会记忆用户设置,用户手动设置后即失效 |
|
| danmaku.unlimited | false | 海量弹幕模式,即使重叠也展示全部弹幕,请注意播放器会记忆用户设置,用户手动设置后即失效 |
|
||||||
|
| danmaku.speedRate | 1 | 弹幕速度倍率,越大速度越快 |
|
||||||
| contextmenu | [] | 自定义右键菜单 |
|
| contextmenu | [] | 自定义右键菜单 |
|
||||||
| highlight | [] | 自定义进度条提示点 |
|
| highlight | [] | 自定义进度条提示点 |
|
||||||
| mutex | true | 互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 |
|
| mutex | true | 互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 |
|
||||||
|
|
@ -162,6 +153,7 @@ const dp = new DPlayer({
|
||||||
user: 'DIYgod',
|
user: 'DIYgod',
|
||||||
bottom: '15%',
|
bottom: '15%',
|
||||||
unlimited: true,
|
unlimited: true,
|
||||||
|
speedRate: 0.5,
|
||||||
},
|
},
|
||||||
contextmenu: [
|
contextmenu: [
|
||||||
{
|
{
|
||||||
|
|
@ -404,15 +396,56 @@ const dp = new DPlayer({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
在使用 `customType` [配合其他 MSE 库使用](#配合其他-mse-库使用)时,需要监听 `destroy` 和 `quality_end` 事件及时销毁 MSE 库实例,避免内存泄漏
|
||||||
|
|
||||||
|
```js
|
||||||
|
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`
|
`danmaku.api`
|
||||||
|
|
||||||
**现成的接口**
|
<!-- **现成的接口**
|
||||||
|
|
||||||
链接: https://api.prprpr.me/dplayer/
|
链接: https://api.prprpr.me/dplayer/ -->
|
||||||
|
|
||||||
每日备份: [DPlayer-data](https://github.com/DIYgod/DPlayer-data)
|
每日备份: [DPlayer-data](https://github.com/DIYgod/DPlayer-data)
|
||||||
|
|
||||||
|
|
@ -683,26 +716,36 @@ const dp = new DPlayer({
|
||||||
|
|
||||||
### 配合其他 MSE 库使用
|
### 配合其他 MSE 库使用
|
||||||
|
|
||||||
DPlayer 可以通过 `customType` 参数与任何 MSE 库一起使用
|
DPlayer 可以通过 `customType` 参数与任何 MSE 库一起使用,例如支持 P2P 插件:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div id="dplayer"></div>
|
<div id="dplayer"></div>
|
||||||
<script src="pearplayer.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/cdnbye@latest"></script>
|
||||||
<script src="DPlayer.min.js"></script>
|
<script src="DPlayer.min.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var type = 'normal';
|
||||||
|
if (Hls.isSupported() && Hls.WEBRTC_SUPPORT) {
|
||||||
|
type = 'customHls';
|
||||||
|
}
|
||||||
const dp = new DPlayer({
|
const dp = new DPlayer({
|
||||||
container: document.getElementById('dplayer'),
|
container: document.getElementById('dplayer'),
|
||||||
video: {
|
video: {
|
||||||
url: 'https://qq.webrtc.win/tv/Pear-Demo-Yosemite_National_Park.mp4',
|
url: 'demo.m3u8',
|
||||||
type: 'pearplayer',
|
type: type,
|
||||||
customType: {
|
customType: {
|
||||||
pearplayer: function (video, player) {
|
customHls: function (video, player) {
|
||||||
new PearPlayer(video, {
|
const hls = new Hls({
|
||||||
src: video.src,
|
debug: false,
|
||||||
autoplay: player.options.autoplay,
|
// 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);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -729,13 +772,13 @@ const dp = new DPlayer({
|
||||||
live: true,
|
live: true,
|
||||||
danmaku: true,
|
danmaku: true,
|
||||||
apiBackend: {
|
apiBackend: {
|
||||||
read: function (endpoint, callback) {
|
read: function (options) {
|
||||||
console.log('Pretend to connect WebSocket');
|
console.log('Pretend to connect WebSocket');
|
||||||
callback();
|
options.success([]);
|
||||||
},
|
},
|
||||||
send: function (endpoint, danmakuData, callback) {
|
send: function (options) {
|
||||||
console.log('Pretend to send danmaku via WebSocket', danmakuData);
|
console.log('Pretend to send danmaku via WebSocket', options.data);
|
||||||
callback();
|
options.success();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
video: {
|
video: {
|
||||||
|
|
|
||||||
|
|
@ -10,45 +10,31 @@ DPlayer 是采用 MIT 许可的开源项目,使用完全免费。 但是随着
|
||||||
|
|
||||||
如果你是个人开发者并且享受 DPlayer 带来的高开发效率,可以用捐助来表示你的谢意 —— 比如偶尔给我买杯咖啡 :)
|
如果你是个人开发者并且享受 DPlayer 带来的高开发效率,可以用捐助来表示你的谢意 —— 比如偶尔给我买杯咖啡 :)
|
||||||
|
|
||||||
你可以通过下列的方法来赞助 DPlayer 的开发。
|
你可以通过下列的方法来赞助 DPlayer 的开发.
|
||||||
|
|
||||||
## 一次性赞助
|
|
||||||
|
|
||||||
我们通过以下方式接受赞助:
|
|
||||||
|
|
||||||
- [微信支付](https://i.imgur.com/aq6PtWa.png)
|
|
||||||
- [支付宝](https://i.imgur.com/wv1Pj2k.png)
|
|
||||||
- [Paypal](https://www.paypal.me/DIYgod)
|
|
||||||
|
|
||||||
## 周期性赞助
|
## 周期性赞助
|
||||||
|
|
||||||
周期性赞助可以获得额外的回报,比如你的名字或你的公司 logo 会出现在 DPlayer 的 GitHub 仓库和现在我们的官网中。
|
- 通过 [GitHub](https://github.com/sponsors/DIYgod) 赞助
|
||||||
|
|
||||||
- 通过 [Patreon](https://www.patreon.com/DIYgod) 赞助
|
- 通过 [Patreon](https://www.patreon.com/DIYgod) 赞助
|
||||||
- 给我们发邮件联系赞助事宜: i#diygod.me
|
- 通过 [爱发电](https://afdian.net/@diygod) 赞助
|
||||||
|
- 给我们发邮件联系赞助事宜: <i@diygod.me>
|
||||||
|
|
||||||
## 当前的顶级赞助商
|
## 一次性赞助
|
||||||
|
|
||||||
### Special Sponsors
|
我们通过以下方式接受赞助:
|
||||||
|
|
||||||
<div>
|
- [微信支付](https://diygod.me/images/wx.jpg)
|
||||||
<a href="https://www.cdnbye.com" target="_blank">
|
- [支付宝](https://diygod.me/images/zfb.jpg)
|
||||||
<img height="60px" src="https://cdnbye.oss-cn-beijing.aliyuncs.com/pic/cdnbye-dp.jpeg">
|
- [Paypal](https://www.paypal.me/DIYgod)
|
||||||
</a>
|
|
||||||
</div>
|
## 赞助商
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
||||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
| [极酷社](https://www.acg.app) |
|
|
||||||
| :---------------------------: |
|
|
||||||
|
|
||||||
|
|
||||||
## DPlayer 贡献者
|
## DPlayer 贡献者
|
||||||
|
|
||||||
感谢所有贡献者。
|
感谢所有贡献者。
|
||||||
|
|
|
||||||
74
package.json
74
package.json
|
|
@ -1,18 +1,20 @@
|
||||||
{
|
{
|
||||||
"name": "dplayer",
|
"name": "dplayer",
|
||||||
"version": "1.26.0",
|
"version": "1.27.1",
|
||||||
"description": "Wow, such a lovely HTML5 danmaku video player",
|
"description": "Wow, such a lovely HTML5 danmaku video player",
|
||||||
"main": "dist/DPlayer.min.js",
|
"main": "dist/DPlayer.min.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run dev",
|
"start": "npm run dev",
|
||||||
"build": "cross-env NODE_ENV=production webpack --config webpack/prod.config.js --progress --display-error-details --colors",
|
"build": "cross-env NODE_ENV=production webpack --config webpack/prod.config.js --progress",
|
||||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack/dev.config.js --watch --colors",
|
"dev": "cross-env NODE_ENV=development webpack serve --config webpack/dev.config.js",
|
||||||
"test": "eslint src webpack",
|
"test": "",
|
||||||
"format": "eslint \"**/*.js\" --fix && prettier \"**/*.{js,json,md}\" --write",
|
"format": "prettier \"**/*.{js,json,md}\" --write",
|
||||||
"format:staged": "eslint \"**/*.js\" --fix && pretty-quick --staged --verbose --pattern \"**/*.{js,json,md}\"",
|
|
||||||
"format:check": "eslint \"**/*.js\" && prettier-check \"**/*.{js,json,md}\"",
|
|
||||||
"docs:dev": "vuepress dev docs",
|
"docs:dev": "vuepress dev docs",
|
||||||
"docs:build": "vuepress build docs"
|
"docs:build": "vuepress build docs",
|
||||||
|
"prepare": "husky install"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"**/*": "prettier --write --ignore-unknown"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|
@ -27,9 +29,6 @@
|
||||||
"video",
|
"video",
|
||||||
"html5"
|
"html5"
|
||||||
],
|
],
|
||||||
"gitHooks": {
|
|
||||||
"pre-commit": "npm run format:staged"
|
|
||||||
},
|
|
||||||
"author": "DIYgod",
|
"author": "DIYgod",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
@ -37,46 +36,43 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/DIYgod/DPlayer#readme",
|
"homepage": "https://github.com/DIYgod/DPlayer#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.6.0",
|
"@babel/core": "^7.22.10",
|
||||||
"@babel/preset-env": "^7.4.5",
|
"@babel/preset-env": "^7.22.10",
|
||||||
"@vuepress/plugin-back-to-top": "1.5.1",
|
"@vuepress/plugin-pwa": "1.9.9",
|
||||||
"@vuepress/plugin-google-analytics": "1.5.1",
|
|
||||||
"@vuepress/plugin-pwa": "1.5.1",
|
|
||||||
"art-template": "4.13.2",
|
"art-template": "4.13.2",
|
||||||
"art-template-loader": "1.4.3",
|
"art-template-loader": "1.4.3",
|
||||||
"autoprefixer": "^9.6.1",
|
"autoprefixer": "^10.4.15",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^9.1.3",
|
||||||
"cross-env": "^7.0.0",
|
"cross-env": "^7.0.0",
|
||||||
"css-loader": "^3.2.0",
|
"css-loader": "^6.8.1",
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^6.0.1",
|
||||||
"eslint": "^7.0.0",
|
"exports-loader": "^4.0.0",
|
||||||
"eslint-config-prettier": "^6.3.0",
|
|
||||||
"eslint-loader": "^4.0.0",
|
|
||||||
"eslint-plugin-prettier": "^3.1.1",
|
|
||||||
"exports-loader": "^0.7.0",
|
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
"git-revision-webpack-plugin": "^3.0.3",
|
"git-revision-webpack-plugin": "^5.0.0",
|
||||||
"mini-css-extract-plugin": "0.9.0",
|
"husky": "^8.0.3",
|
||||||
"node-sass": "^4.12.0",
|
"less": "^4.2.0",
|
||||||
"postcss-loader": "^3.0.0",
|
"less-loader": "^11.1.3",
|
||||||
"prettier": "^2.0.4",
|
"lint-staged": "^13.3.0",
|
||||||
|
"mini-css-extract-plugin": "2.7.6",
|
||||||
|
"postcss": "^8.4.27",
|
||||||
|
"postcss-loader": "^7.3.3",
|
||||||
|
"postcss-preset-env": "^9.1.1",
|
||||||
|
"prettier": "^3.0.1",
|
||||||
"prettier-check": "^2.0.0",
|
"prettier-check": "^2.0.0",
|
||||||
"pretty-quick": "^2.0.0",
|
"pretty-quick": "^3.0.0",
|
||||||
"sass-loader": "^8.0.0",
|
|
||||||
"strip-loader": "^0.1.2",
|
"strip-loader": "^0.1.2",
|
||||||
"style-loader": "^1.0.0",
|
"style-loader": "^3.3.3",
|
||||||
"svg-inline-loader": "0.8.2",
|
"svg-inline-loader": "0.8.2",
|
||||||
"template-string-optimize-loader": "^3.0.0",
|
"template-string-optimize-loader": "^3.0.0",
|
||||||
"url-loader": "^4.1.0",
|
"url-loader": "^4.1.0",
|
||||||
"vuepress": "1.5.1",
|
"webpack": "^5.88.2",
|
||||||
"webpack": "^4.40.2",
|
"webpack-cli": "5.1.4",
|
||||||
"webpack-cli": "3.3.11",
|
"webpack-dev-server": "^4.15.1",
|
||||||
"webpack-dev-server": "^3.8.1",
|
|
||||||
"yorkie": "^2.0.0"
|
"yorkie": "^2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "0.19.2",
|
"axios": "1.4.0",
|
||||||
"balloon-css": "^1.0.3",
|
"balloon-css": "^1.0.3",
|
||||||
"promise-polyfill": "8.1.3"
|
"promise-polyfill": "8.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1 @@
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="chromecast" class="svg-inline--fa fa-chromecast fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M447.8,64H64c-23.6,0-42.7,19.1-42.7,42.7v63.9H64v-63.9h383.8v298.6H298.6V448H448c23.6,0,42.7-19.1,42.7-42.7V106.7 C490.7,83.1,471.4,64,447.8,64z M21.3,383.6L21.3,383.6l0,63.9h63.9C85.2,412.2,56.6,383.6,21.3,383.6L21.3,383.6z M21.3,298.6V341 c58.9,0,106.6,48.1,106.6,107h42.7C170.7,365.6,103.7,298.7,21.3,298.6z M213.4,448h42.7c-0.5-129.5-105.3-234.3-234.8-234.6l0,42.4 C127.3,255.6,213.3,342,213.4,448z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 642 B |
|
|
@ -60,11 +60,11 @@
|
||||||
animation: diplayer-loading-dot-fade .8s ease infinite;
|
animation: diplayer-loading-dot-fade .8s ease infinite;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform-origin: 4px 4px;
|
transform-origin: 4px 4px;
|
||||||
@for $i from 7 through 1 {
|
each(range(7), {
|
||||||
&.diplayer-loading-dot-#{$i} {
|
&.diplayer-loading-dot-@{value} {
|
||||||
animation-delay: .1s * $i;
|
animation-delay: (@value * 0.1s);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
@keyframes diplayer-loading-dot-fade {
|
@keyframes diplayer-loading-dot-fade {
|
||||||
0% {
|
0% {
|
||||||
|
|
@ -408,6 +408,41 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
.dplayer-subtitles {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
.dplayer-subtitles-box {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 50px;
|
||||||
|
transform: scale(0);
|
||||||
|
width: fit-content;
|
||||||
|
max-width: 240px;
|
||||||
|
min-width: 120px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(28, 28, 28, 0.9);
|
||||||
|
padding: 7px 0;
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
|
overflow: auto;
|
||||||
|
z-index: 2;
|
||||||
|
&.dplayer-subtitles-panel {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
&.dplayer-subtitles-box-open {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dplayer-subtitles-item {
|
||||||
|
height: 30px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, .1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.dplayer-setting {
|
.dplayer-setting {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-shadow: .5px .5px .5px rgba(0, 0, 0, .5);
|
text-shadow: 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.5);
|
||||||
&--demo {
|
&--demo {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|
@ -24,7 +24,8 @@
|
||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
&.dplayer-danmaku-move {
|
&.dplayer-danmaku-move {
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
animation: danmaku 5s linear;
|
animation-name: danmaku;
|
||||||
|
animation-timing-function: linear;
|
||||||
animation-play-state: paused;
|
animation-play-state: paused;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,7 +42,8 @@
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
&.dplayer-danmaku-move {
|
&.dplayer-danmaku-move {
|
||||||
will-change: visibility;
|
will-change: visibility;
|
||||||
animation: danmaku-center 4s linear;
|
animation-name: danmaku-center;
|
||||||
|
animation-timing-function: linear;
|
||||||
animation-play-state: paused;
|
animation-play-state: paused;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
.dplayer-notice-list{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 60px;
|
||||||
|
left: 20px;
|
||||||
|
|
||||||
|
.dplayer-notice {
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(28, 28, 28, 0.9);
|
||||||
|
transition: all .3s ease-in-out;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #fff;
|
||||||
|
display: table;
|
||||||
|
pointer-events: none;
|
||||||
|
animation: showNotice .3s ease 1 forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-notice{
|
||||||
|
animation: removeNotice .3s ease 1 forwards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes showNotice {
|
||||||
|
from {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
padding: 7px 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes removeNotice {
|
||||||
|
0%{
|
||||||
|
padding: 7px 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
20%{
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
21%{
|
||||||
|
font-size: 0;
|
||||||
|
padding: 7px 10px;
|
||||||
|
}
|
||||||
|
100%{
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
.dplayer-notice {
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 60px;
|
|
||||||
left: 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
border-radius: 2px;
|
|
||||||
background: rgba(28, 28, 28, 0.9);
|
|
||||||
padding: 7px 20px;
|
|
||||||
transition: all .3s ease-in-out;
|
|
||||||
overflow: hidden;
|
|
||||||
color: #fff;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
@ -30,22 +30,6 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
transform: translate(0, 0);
|
transform: translate(0, 0);
|
||||||
|
|
||||||
.dplayer-danmaku {
|
|
||||||
.dplayer-danmaku-top,
|
|
||||||
.dplayer-danmaku-bottom {
|
|
||||||
&.dplayer-danmaku-move {
|
|
||||||
animation: danmaku-center 6s linear;
|
|
||||||
animation-play-state: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dplayer-danmaku-right {
|
|
||||||
&.dplayer-danmaku-move {
|
|
||||||
animation: danmaku 8s linear;
|
|
||||||
animation-play-state: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.dplayer-no-danmaku {
|
&.dplayer-no-danmaku {
|
||||||
|
|
@ -167,6 +151,7 @@
|
||||||
.dplayer-volume,
|
.dplayer-volume,
|
||||||
.dplayer-camera-icon,
|
.dplayer-camera-icon,
|
||||||
.dplayer-airplay-icon,
|
.dplayer-airplay-icon,
|
||||||
|
.dplayer-chromecast-icon,
|
||||||
.dplayer-play-icon {
|
.dplayer-play-icon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ class Comment {
|
||||||
|
|
||||||
// text can't be empty
|
// text can't be empty
|
||||||
if (!this.player.template.commentInput.value.replace(/^\s+|\s+$/g, '')) {
|
if (!this.player.template.commentInput.value.replace(/^\s+|\s+$/g, '')) {
|
||||||
this.player.notice(this.player.tran('Please input danmaku content!'));
|
this.player.notice(this.player.tran('please-input-danmaku'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class ContextMenu {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.player.container.addEventListener('contextmenu', (e) => {
|
this.contextmenuHandler = (e) => {
|
||||||
if (this.shown) {
|
if (this.shown) {
|
||||||
this.hide();
|
this.hide();
|
||||||
return;
|
return;
|
||||||
|
|
@ -27,7 +27,8 @@ class ContextMenu {
|
||||||
this.player.template.mask.addEventListener('click', () => {
|
this.player.template.mask.addEventListener('click', () => {
|
||||||
this.hide();
|
this.hide();
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
this.player.container.addEventListener('contextmenu', this.contextmenuHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
show(x, y) {
|
show(x, y) {
|
||||||
|
|
@ -62,6 +63,10 @@ class ContextMenu {
|
||||||
this.shown = false;
|
this.shown = false;
|
||||||
this.player.events.trigger('contextmenu_hide');
|
this.player.events.trigger('contextmenu_hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.player.container.removeEventListener('contextmenu', this.contextmenuHandler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ContextMenu;
|
export default ContextMenu;
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,21 @@ import utils from './utils';
|
||||||
import Thumbnails from './thumbnails';
|
import Thumbnails from './thumbnails';
|
||||||
import Icons from './icons';
|
import Icons from './icons';
|
||||||
|
|
||||||
|
let cast;
|
||||||
|
let runOnce = true;
|
||||||
|
let isCasting = false;
|
||||||
|
|
||||||
class Controller {
|
class Controller {
|
||||||
constructor(player) {
|
constructor(player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
|
||||||
this.autoHideTimer = 0;
|
this.autoHideTimer = 0;
|
||||||
if (!utils.isMobile) {
|
if (!utils.isMobile) {
|
||||||
this.player.container.addEventListener('mousemove', () => {
|
this.setAutoHideHandler = this.setAutoHide.bind(this);
|
||||||
this.setAutoHide();
|
this.player.container.addEventListener('mousemove', this.setAutoHideHandler);
|
||||||
});
|
this.player.container.addEventListener('click', this.setAutoHideHandler);
|
||||||
this.player.container.addEventListener('click', () => {
|
this.player.on('play', this.setAutoHideHandler);
|
||||||
this.setAutoHide();
|
this.player.on('pause', this.setAutoHideHandler);
|
||||||
});
|
|
||||||
this.player.on('play', () => {
|
|
||||||
this.setAutoHide();
|
|
||||||
});
|
|
||||||
this.player.on('pause', () => {
|
|
||||||
this.setAutoHide();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initPlayButton();
|
this.initPlayButton();
|
||||||
|
|
@ -28,11 +25,15 @@ class Controller {
|
||||||
this.initFullButton();
|
this.initFullButton();
|
||||||
this.initQualityButton();
|
this.initQualityButton();
|
||||||
this.initScreenshotButton();
|
this.initScreenshotButton();
|
||||||
this.initSubtitleButton();
|
// if subtitle url not array, not init old single subtitle button
|
||||||
this.initHighlights();
|
if (this.player.options.subtitle) {
|
||||||
if (utils.isSafari) {
|
if (typeof this.player.options.subtitle.url === 'string') {
|
||||||
this.initAirplayButton();
|
this.initSubtitleButton();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.initHighlights();
|
||||||
|
this.initAirplayButton();
|
||||||
|
this.initChromecastButton();
|
||||||
if (!utils.isMobile) {
|
if (!utils.isMobile) {
|
||||||
this.initVolumeButton();
|
this.initVolumeButton();
|
||||||
}
|
}
|
||||||
|
|
@ -48,12 +49,14 @@ class Controller {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!utils.isMobile) {
|
if (!utils.isMobile) {
|
||||||
this.player.template.videoWrap.addEventListener('click', () => {
|
if (!this.player.options.preventClickToggle) {
|
||||||
this.player.toggle();
|
this.player.template.videoWrap.addEventListener('click', () => {
|
||||||
});
|
this.player.toggle();
|
||||||
this.player.template.controllerMask.addEventListener('click', () => {
|
});
|
||||||
this.player.toggle();
|
this.player.template.controllerMask.addEventListener('click', () => {
|
||||||
});
|
this.player.toggle();
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.player.template.videoWrap.addEventListener('click', () => {
|
this.player.template.videoWrap.addEventListener('click', () => {
|
||||||
this.toggle();
|
this.toggle();
|
||||||
|
|
@ -68,7 +71,7 @@ class Controller {
|
||||||
this.player.on('durationchange', () => {
|
this.player.on('durationchange', () => {
|
||||||
if (this.player.video.duration !== 1 && this.player.video.duration !== Infinity) {
|
if (this.player.video.duration !== 1 && this.player.video.duration !== Infinity) {
|
||||||
if (this.player.options.highlight) {
|
if (this.player.options.highlight) {
|
||||||
const highlights = document.querySelectorAll('.dplayer-highlight');
|
const highlights = this.player.template.playedBarWrap.querySelectorAll('.dplayer-highlight');
|
||||||
[].slice.call(highlights, 0).forEach((item) => {
|
[].slice.call(highlights, 0).forEach((item) => {
|
||||||
this.player.template.playedBarWrap.removeChild(item);
|
this.player.template.playedBarWrap.removeChild(item);
|
||||||
});
|
});
|
||||||
|
|
@ -119,11 +122,11 @@ class Controller {
|
||||||
percentage = Math.min(percentage, 1);
|
percentage = Math.min(percentage, 1);
|
||||||
this.player.bar.set('played', percentage, 'width');
|
this.player.bar.set('played', percentage, 'width');
|
||||||
this.player.seek(this.player.bar.get('played') * this.player.video.duration);
|
this.player.seek(this.player.bar.get('played') * this.player.video.duration);
|
||||||
this.player.timer.enable('progress');
|
this.player.moveBar = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.player.template.playedBarWrap.addEventListener(utils.nameMap.dragStart, () => {
|
this.player.template.playedBarWrap.addEventListener(utils.nameMap.dragStart, () => {
|
||||||
this.player.timer.disable('progress');
|
this.player.moveBar = true;
|
||||||
document.addEventListener(utils.nameMap.dragMove, thumbMove);
|
document.addEventListener(utils.nameMap.dragMove, thumbMove);
|
||||||
document.addEventListener(utils.nameMap.dragEnd, thumbUp);
|
document.addEventListener(utils.nameMap.dragEnd, thumbUp);
|
||||||
});
|
});
|
||||||
|
|
@ -245,9 +248,8 @@ class Controller {
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
URL.revokeObjectURL(dataURL);
|
URL.revokeObjectURL(dataURL);
|
||||||
|
this.player.events.trigger('screenshot', dataURL);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.player.events.trigger('screenshot', dataURL);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -281,25 +283,103 @@ class Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initSubtitleButton() {
|
initChromecast() {
|
||||||
if (this.player.options.subtitle) {
|
const script = window.document.createElement('script');
|
||||||
this.player.events.on('subtitle_show', () => {
|
script.setAttribute('type', 'text/javascript');
|
||||||
this.player.template.subtitleButton.dataset.balloon = this.player.tran('Hide subtitle');
|
script.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1');
|
||||||
this.player.template.subtitleButtonInner.style.opacity = '';
|
window.document.body.appendChild(script);
|
||||||
this.player.user.set('subtitle', 1);
|
|
||||||
});
|
|
||||||
this.player.events.on('subtitle_hide', () => {
|
|
||||||
this.player.template.subtitleButton.dataset.balloon = this.player.tran('Show subtitle');
|
|
||||||
this.player.template.subtitleButtonInner.style.opacity = '0.4';
|
|
||||||
this.player.user.set('subtitle', 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.player.template.subtitleButton.addEventListener('click', () => {
|
window.__onGCastApiAvailable = (isAvailable) => {
|
||||||
this.player.subtitle.toggle();
|
if (isAvailable) {
|
||||||
|
cast = window.chrome.cast;
|
||||||
|
const sessionRequest = new cast.SessionRequest(cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID);
|
||||||
|
const apiConfig = new cast.ApiConfig(
|
||||||
|
sessionRequest,
|
||||||
|
() => {},
|
||||||
|
(status) => {
|
||||||
|
if (status === cast.ReceiverAvailability.AVAILABLE) {
|
||||||
|
console.log('chromecast: ', status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
cast.initialize(apiConfig, () => {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
initChromecastButton() {
|
||||||
|
if (this.player.options.chromecast) {
|
||||||
|
if (runOnce) {
|
||||||
|
runOnce = false;
|
||||||
|
this.initChromecast();
|
||||||
|
}
|
||||||
|
const discoverDevices = () => {
|
||||||
|
cast.requestSession(
|
||||||
|
(s) => {
|
||||||
|
this.session = s;
|
||||||
|
launchMedia(this.player.options.video.url);
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
if (err.code === 'cancel') {
|
||||||
|
this.session = undefined;
|
||||||
|
} else {
|
||||||
|
console.error('Error selecting a cast device', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const launchMedia = (media) => {
|
||||||
|
const mediaInfo = new cast.media.MediaInfo(media);
|
||||||
|
const request = new cast.media.LoadRequest(mediaInfo);
|
||||||
|
|
||||||
|
if (!this.session) {
|
||||||
|
window.open(media);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.session.loadMedia(request, onMediaDiscovered.bind(this, 'loadMedia'), onMediaError).play();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMediaDiscovered = (how, media) => {
|
||||||
|
this.currentMedia = media;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMediaError = (err) => {
|
||||||
|
console.error('Error launching media', err);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.player.template.chromecastButton.addEventListener('click', () => {
|
||||||
|
if (isCasting) {
|
||||||
|
isCasting = false;
|
||||||
|
this.currentMedia.stop();
|
||||||
|
this.session.stop();
|
||||||
|
this.initChromecast();
|
||||||
|
} else {
|
||||||
|
isCasting = true;
|
||||||
|
discoverDevices();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initSubtitleButton() {
|
||||||
|
this.player.events.on('subtitle_show', () => {
|
||||||
|
this.player.template.subtitleButton.dataset.balloon = this.player.tran('hide-subs');
|
||||||
|
this.player.template.subtitleButtonInner.style.opacity = '';
|
||||||
|
this.player.user.set('subtitle', 1);
|
||||||
|
});
|
||||||
|
this.player.events.on('subtitle_hide', () => {
|
||||||
|
this.player.template.subtitleButton.dataset.balloon = this.player.tran('show-subs');
|
||||||
|
this.player.template.subtitleButtonInner.style.opacity = '0.4';
|
||||||
|
this.player.user.set('subtitle', 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.player.template.subtitleButton.addEventListener('click', () => {
|
||||||
|
this.player.subtitle.toggle();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setAutoHide() {
|
setAutoHide() {
|
||||||
this.show();
|
this.show();
|
||||||
clearTimeout(this.autoHideTimer);
|
clearTimeout(this.autoHideTimer);
|
||||||
|
|
@ -333,6 +413,10 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
if (!utils.isMobile) {
|
||||||
|
this.player.container.removeEventListener('mousemove', this.setAutoHideHandler);
|
||||||
|
this.player.container.removeEventListener('click', this.setAutoHideHandler);
|
||||||
|
}
|
||||||
clearTimeout(this.autoHideTimer);
|
clearTimeout(this.autoHideTimer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import utils from './utils';
|
||||||
class Danmaku {
|
class Danmaku {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
this.player = this.options.player;
|
||||||
this.container = this.options.container;
|
this.container = this.options.container;
|
||||||
this.danTunnel = {
|
this.danTunnel = {
|
||||||
right: {},
|
right: {},
|
||||||
|
|
@ -69,7 +70,7 @@ class Danmaku {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: (msg) => {
|
error: (msg) => {
|
||||||
this.options.error(msg || this.options.tran('Danmaku load failed'));
|
this.options.error(msg || this.options.tran('danmaku-failed'));
|
||||||
results[i] = [];
|
results[i] = [];
|
||||||
|
|
||||||
++readCount;
|
++readCount;
|
||||||
|
|
@ -96,7 +97,7 @@ class Danmaku {
|
||||||
data: danmakuData,
|
data: danmakuData,
|
||||||
success: callback,
|
success: callback,
|
||||||
error: (msg) => {
|
error: (msg) => {
|
||||||
this.options.error(msg || this.options.tran('Danmaku send failed'));
|
this.options.error(msg || this.options.tran('danmaku-failed'));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -254,6 +255,7 @@ class Danmaku {
|
||||||
if (tunnel >= 0) {
|
if (tunnel >= 0) {
|
||||||
// move
|
// move
|
||||||
item.classList.add('dplayer-danmaku-move');
|
item.classList.add('dplayer-danmaku-move');
|
||||||
|
item.style.animationDuration = this._danAnimation(dan[i].type);
|
||||||
|
|
||||||
// insert
|
// insert
|
||||||
docFragment.appendChild(item);
|
docFragment.appendChild(item);
|
||||||
|
|
@ -307,13 +309,7 @@ class Danmaku {
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlEncode(str) {
|
htmlEncode(str) {
|
||||||
return str
|
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/');
|
||||||
.replace(/&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/'/g, ''')
|
|
||||||
.replace(/\//g, '/');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resize() {
|
resize() {
|
||||||
|
|
@ -343,6 +339,21 @@ class Danmaku {
|
||||||
unlimit(boolean) {
|
unlimit(boolean) {
|
||||||
this.unlimited = boolean;
|
this.unlimited = boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
speed(rate) {
|
||||||
|
this.options.api.speedRate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
_danAnimation(position) {
|
||||||
|
const rate = this.options.api.speedRate || 1;
|
||||||
|
const isFullScreen = !!this.player.fullScreen.isFullScreen();
|
||||||
|
const animations = {
|
||||||
|
top: `${(isFullScreen ? 6 : 4) / rate}s`,
|
||||||
|
right: `${(isFullScreen ? 8 : 5) / rate}s`,
|
||||||
|
bottom: `${(isFullScreen ? 6 : 4) / rate}s`,
|
||||||
|
};
|
||||||
|
return animations[position];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Danmaku;
|
export default Danmaku;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ class FullScreen {
|
||||||
utils.setScrollPosition(this.lastScrollPosition);
|
utils.setScrollPosition(this.lastScrollPosition);
|
||||||
});
|
});
|
||||||
|
|
||||||
const fullscreenchange = () => {
|
this.fullscreenchange = () => {
|
||||||
this.player.resize();
|
this.player.resize();
|
||||||
if (this.isFullScreen('browser')) {
|
if (this.isFullScreen('browser')) {
|
||||||
this.player.events.trigger('fullscreen');
|
this.player.events.trigger('fullscreen');
|
||||||
|
|
@ -21,7 +21,7 @@ class FullScreen {
|
||||||
this.player.events.trigger('fullscreen_cancel');
|
this.player.events.trigger('fullscreen_cancel');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const docfullscreenchange = () => {
|
this.docfullscreenchange = () => {
|
||||||
const fullEle = document.fullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
|
const fullEle = document.fullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
|
||||||
if (fullEle && fullEle !== this.player.container) {
|
if (fullEle && fullEle !== this.player.container) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -35,13 +35,13 @@ class FullScreen {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (/Firefox/.test(navigator.userAgent)) {
|
if (/Firefox/.test(navigator.userAgent)) {
|
||||||
document.addEventListener('mozfullscreenchange', docfullscreenchange);
|
document.addEventListener('mozfullscreenchange', this.docfullscreenchange);
|
||||||
document.addEventListener('fullscreenchange', docfullscreenchange);
|
document.addEventListener('fullscreenchange', this.docfullscreenchange);
|
||||||
} else {
|
} else {
|
||||||
this.player.container.addEventListener('fullscreenchange', fullscreenchange);
|
this.player.container.addEventListener('fullscreenchange', this.fullscreenchange);
|
||||||
this.player.container.addEventListener('webkitfullscreenchange', fullscreenchange);
|
this.player.container.addEventListener('webkitfullscreenchange', this.fullscreenchange);
|
||||||
document.addEventListener('msfullscreenchange', docfullscreenchange);
|
document.addEventListener('msfullscreenchange', this.docfullscreenchange);
|
||||||
document.addEventListener('MSFullscreenChange', docfullscreenchange);
|
document.addEventListener('MSFullscreenChange', this.docfullscreenchange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,6 +122,18 @@ class FullScreen {
|
||||||
this.request(type);
|
this.request(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
if (/Firefox/.test(navigator.userAgent)) {
|
||||||
|
document.removeEventListener('mozfullscreenchange', this.docfullscreenchange);
|
||||||
|
document.removeEventListener('fullscreenchange', this.docfullscreenchange);
|
||||||
|
} else {
|
||||||
|
this.player.container.removeEventListener('fullscreenchange', this.fullscreenchange);
|
||||||
|
this.player.container.removeEventListener('webkitfullscreenchange', this.fullscreenchange);
|
||||||
|
document.removeEventListener('msfullscreenchange', this.docfullscreenchange);
|
||||||
|
document.removeEventListener('MSFullscreenChange', this.docfullscreenchange);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FullScreen;
|
export default FullScreen;
|
||||||
|
|
|
||||||
118
src/js/hotkey.js
118
src/js/hotkey.js
|
|
@ -1,60 +1,74 @@
|
||||||
class HotKey {
|
class HotKey {
|
||||||
constructor(player) {
|
constructor(player) {
|
||||||
if (player.options.hotkey) {
|
this.player = player;
|
||||||
document.addEventListener('keydown', (e) => {
|
this.doHotKeyHandler = this.doHotKey.bind(this);
|
||||||
if (player.focus) {
|
this.cancelFullScreenHandler = this.cancelFullScreen.bind(this);
|
||||||
const tag = document.activeElement.tagName.toUpperCase();
|
if (this.player.options.hotkey) {
|
||||||
const editable = document.activeElement.getAttribute('contenteditable');
|
document.addEventListener('keydown', this.doHotKeyHandler);
|
||||||
if (tag !== 'INPUT' && tag !== 'TEXTAREA' && editable !== '' && editable !== 'true') {
|
|
||||||
const event = e || window.event;
|
|
||||||
let percentage;
|
|
||||||
switch (event.keyCode) {
|
|
||||||
case 32:
|
|
||||||
event.preventDefault();
|
|
||||||
player.toggle();
|
|
||||||
break;
|
|
||||||
case 37:
|
|
||||||
event.preventDefault();
|
|
||||||
if (player.options.live) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
player.seek(player.video.currentTime - 5);
|
|
||||||
player.controller.setAutoHide();
|
|
||||||
break;
|
|
||||||
case 39:
|
|
||||||
event.preventDefault();
|
|
||||||
if (player.options.live) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
player.seek(player.video.currentTime + 5);
|
|
||||||
player.controller.setAutoHide();
|
|
||||||
break;
|
|
||||||
case 38:
|
|
||||||
event.preventDefault();
|
|
||||||
percentage = player.volume() + 0.1;
|
|
||||||
player.volume(percentage);
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
event.preventDefault();
|
|
||||||
percentage = player.volume() - 0.1;
|
|
||||||
player.volume(percentage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', this.cancelFullScreenHandler);
|
||||||
const event = e || window.event;
|
}
|
||||||
switch (event.keyCode) {
|
|
||||||
case 27:
|
doHotKey(e) {
|
||||||
if (player.fullScreen.isFullScreen('web')) {
|
if (this.player.focus) {
|
||||||
player.fullScreen.cancel('web');
|
const tag = document.activeElement.tagName.toUpperCase();
|
||||||
}
|
const editable = document.activeElement.getAttribute('contenteditable');
|
||||||
break;
|
if (tag !== 'INPUT' && tag !== 'TEXTAREA' && editable !== '' && editable !== 'true') {
|
||||||
|
const event = e || window.event;
|
||||||
|
let percentage;
|
||||||
|
switch (event.keyCode) {
|
||||||
|
case 32:
|
||||||
|
event.preventDefault();
|
||||||
|
this.player.toggle();
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
event.preventDefault();
|
||||||
|
if (this.player.options.live) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.player.seek(this.player.video.currentTime - 5);
|
||||||
|
this.player.controller.setAutoHide();
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
event.preventDefault();
|
||||||
|
if (this.player.options.live) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.player.seek(this.player.video.currentTime + 5);
|
||||||
|
this.player.controller.setAutoHide();
|
||||||
|
break;
|
||||||
|
case 38:
|
||||||
|
event.preventDefault();
|
||||||
|
percentage = this.player.volume() + 0.1;
|
||||||
|
this.player.volume(percentage);
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
event.preventDefault();
|
||||||
|
percentage = this.player.volume() - 0.1;
|
||||||
|
this.player.volume(percentage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelFullScreen(e) {
|
||||||
|
const event = e || window.event;
|
||||||
|
switch (event.keyCode) {
|
||||||
|
case 27:
|
||||||
|
if (this.player.fullScreen.isFullScreen('web')) {
|
||||||
|
this.player.fullScreen.cancel('web');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
if (this.player.options.hotkey) {
|
||||||
|
document.removeEventListener('keydown', this.doHotKeyHandler);
|
||||||
|
}
|
||||||
|
document.removeEventListener('keydown', this.cancelFullScreenHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
423
src/js/i18n.js
423
src/js/i18n.js
|
|
@ -9,97 +9,358 @@ Use this as shown below..... */
|
||||||
|
|
||||||
function i18n(lang) {
|
function i18n(lang) {
|
||||||
this.lang = lang;
|
this.lang = lang;
|
||||||
this.tran = (text) => {
|
// in case someone says en-us, and en is present!
|
||||||
if (tranTxt[this.lang] && tranTxt[this.lang][text]) {
|
this.fallbackLang = this.lang.includes('-') ? this.lang.split('-')[0] : this.lang;
|
||||||
return tranTxt[this.lang][text];
|
this.tran = (key) => {
|
||||||
|
key = key.toLowerCase();
|
||||||
|
if (tranTxt[this.lang] && tranTxt[this.lang][key]) {
|
||||||
|
return tranTxt[this.lang][key];
|
||||||
|
} else if (tranTxt[this.fallbackLang] && tranTxt[this.fallbackLang][key]) {
|
||||||
|
return tranTxt[this.fallbackLang][key];
|
||||||
|
} else if (standard[key]) {
|
||||||
|
return standard[key];
|
||||||
} else {
|
} else {
|
||||||
return text;
|
return key;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// abstract model for recognizing if valid translations are present
|
||||||
|
// const model = {
|
||||||
|
// 'danmaku-loading': [],
|
||||||
|
// top: [],
|
||||||
|
// bottom: [],
|
||||||
|
// rolling: [],
|
||||||
|
// 'input-danmaku-enter': [],
|
||||||
|
// 'about-author': [],
|
||||||
|
// 'dplayer-feedback': [],
|
||||||
|
// 'about-dplayer': [],
|
||||||
|
// loop: [],
|
||||||
|
// speed: [],
|
||||||
|
// 'opacity-danmaku': [],
|
||||||
|
// normal: [],
|
||||||
|
// 'please-input-danmaku': [],
|
||||||
|
// 'set-danmaku-color': [],
|
||||||
|
// 'set-danmaku-type': [],
|
||||||
|
// 'show-danmaku': [],
|
||||||
|
// 'video-failed': [],
|
||||||
|
// 'danmaku-failed': [],
|
||||||
|
// 'danmaku-send-failed': [],
|
||||||
|
// 'switching-quality': [{ symbol: '%q', name: 'Quality', example: '720p' }],
|
||||||
|
// 'switched-quality': [{ symbol: '%q', name: 'Quality', example: '720p' }],
|
||||||
|
// ff: [{ symbol: '%s', name: 'Seconds', example: '5' }],
|
||||||
|
// rew: [{ symbol: '%s', name: 'Seconds', example: '5' }],
|
||||||
|
// 'unlimited-danmaku': [],
|
||||||
|
// 'send-danmaku': [],
|
||||||
|
// setting: [],
|
||||||
|
// fullscreen: [],
|
||||||
|
// 'web-fullscreen': [],
|
||||||
|
// send: [],
|
||||||
|
// screenshot: [],
|
||||||
|
// airplay: [],
|
||||||
|
// chromecast: [],
|
||||||
|
// 'show-subs': [],
|
||||||
|
// 'hide-subs': [],
|
||||||
|
// volume: [],
|
||||||
|
// live: [],
|
||||||
|
// 'video-info': [],
|
||||||
|
// };
|
||||||
|
|
||||||
|
// Standard english translations
|
||||||
|
const standard = {
|
||||||
|
'danmaku-loading': 'Danmaku is loading',
|
||||||
|
top: 'Top',
|
||||||
|
bottom: 'Bottom',
|
||||||
|
rolling: 'Rolling',
|
||||||
|
'input-danmaku-enter': 'Input danmaku, hit Enter',
|
||||||
|
'about-author': 'About author',
|
||||||
|
'dplayer-feedback': 'DPlayer feedback',
|
||||||
|
'about-dplayer': 'About DPlayer',
|
||||||
|
loop: 'Loop',
|
||||||
|
speed: 'Speed',
|
||||||
|
'opacity-danmaku': 'Opacity for danmaku',
|
||||||
|
normal: 'Normal',
|
||||||
|
'please-input-danmaku': 'Please input danmaku content!',
|
||||||
|
'set-danmaku-color': 'Set danmaku color',
|
||||||
|
'set-danmaku-type': 'Set danmaku type',
|
||||||
|
'show-danmaku': 'Show danmaku',
|
||||||
|
'video-failed': 'Video load failed',
|
||||||
|
'danmaku-failed': 'Danmaku load failed',
|
||||||
|
'danmaku-send-failed': 'Danmaku send failed',
|
||||||
|
'switching-quality': 'Switching to %q quality',
|
||||||
|
'switched-quality': 'Switched to %q quality',
|
||||||
|
ff: 'FF %s s',
|
||||||
|
rew: 'REW %s s',
|
||||||
|
'unlimited-danmaku': 'Unlimited danmaku',
|
||||||
|
'send-danmaku': 'Send danmaku',
|
||||||
|
setting: 'Setting',
|
||||||
|
fullscreen: 'Full screen',
|
||||||
|
'web-fullscreen': 'Web full screen',
|
||||||
|
send: 'Send',
|
||||||
|
screenshot: 'Screenshot',
|
||||||
|
airplay: 'AirPlay',
|
||||||
|
chromecast: 'ChromeCast',
|
||||||
|
subtitle: 'Subtitle',
|
||||||
|
off: 'Off',
|
||||||
|
'show-subs': 'Show subtitle',
|
||||||
|
'hide-subs': 'Hide subtitle',
|
||||||
|
volume: 'Volume',
|
||||||
|
live: 'Live',
|
||||||
|
'video-info': 'Video info',
|
||||||
|
};
|
||||||
|
|
||||||
// add translation text here
|
// add translation text here
|
||||||
const tranTxt = {
|
const tranTxt = {
|
||||||
|
en: standard,
|
||||||
'zh-cn': {
|
'zh-cn': {
|
||||||
'Danmaku is loading': '弹幕加载中',
|
'danmaku-loading': '弹幕加载中',
|
||||||
Top: '顶部',
|
top: '顶部',
|
||||||
Bottom: '底部',
|
bottom: '底部',
|
||||||
Rolling: '滚动',
|
rolling: '滚动',
|
||||||
'Input danmaku, hit Enter': '输入弹幕,回车发送',
|
'input-danmaku-enter': '输入弹幕,回车发送',
|
||||||
'About author': '关于作者',
|
'about-author': '关于作者',
|
||||||
'DPlayer feedback': '播放器意见反馈',
|
'dplayer-feedback': '播放器意见反馈',
|
||||||
'About DPlayer': '关于 DPlayer 播放器',
|
'about-dplayer': '关于 DPlayer 播放器',
|
||||||
Loop: '洗脑循环',
|
loop: '洗脑循环',
|
||||||
Speed: '速度',
|
speed: '速度',
|
||||||
'Opacity for danmaku': '弹幕透明度',
|
'opacity-danmaku': '弹幕透明度',
|
||||||
Normal: '正常',
|
normal: '正常',
|
||||||
'Please input danmaku content!': '要输入弹幕内容啊喂!',
|
'please-input-danmaku': '要输入弹幕内容啊喂!',
|
||||||
'Set danmaku color': '设置弹幕颜色',
|
'set-danmaku-color': '设置弹幕颜色',
|
||||||
'Set danmaku type': '设置弹幕类型',
|
'set-danmaku-type': '设置弹幕类型',
|
||||||
'Show danmaku': '显示弹幕',
|
'show-danmaku': '显示弹幕',
|
||||||
'Video load failed': '视频加载失败',
|
'video-failed': '视频加载失败',
|
||||||
'Danmaku load failed': '弹幕加载失败',
|
'danmaku-failed': '弹幕加载失败',
|
||||||
'Danmaku send failed': '弹幕发送失败',
|
'danmaku-send-failed': '弹幕发送失败',
|
||||||
'Switching to': '正在切换至',
|
'switching-quality': '正在切换至 %q 画质',
|
||||||
'Switched to': '已经切换至',
|
'switched-quality': '已经切换至 %q 画质',
|
||||||
quality: '画质',
|
ff: '快进 %s 秒',
|
||||||
FF: '快进',
|
rew: '快退 %s 秒',
|
||||||
REW: '快退',
|
'unlimited-danmaku': '海量弹幕',
|
||||||
'Unlimited danmaku': '海量弹幕',
|
'send-danmaku': '发送弹幕',
|
||||||
'Send danmaku': '发送弹幕',
|
setting: '设置',
|
||||||
Setting: '设置',
|
fullscreen: '全屏',
|
||||||
'Full screen': '全屏',
|
'web-fullscreen': '页面全屏',
|
||||||
'Web full screen': '页面全屏',
|
send: '发送',
|
||||||
Send: '发送',
|
screenshot: '截图',
|
||||||
Screenshot: '截图',
|
airplay: '无线投屏',
|
||||||
AirPlay: '无线投屏',
|
chromecast: 'ChromeCast',
|
||||||
s: '秒',
|
subtitle: '字幕',
|
||||||
'Show subtitle': '显示字幕',
|
off: '关闭',
|
||||||
'Hide subtitle': '隐藏字幕',
|
'show-subs': '显示字幕',
|
||||||
Volume: '音量',
|
'hide-subs': '隐藏字幕',
|
||||||
Live: '直播',
|
volume: '音量',
|
||||||
'Video info': '视频统计信息',
|
live: '直播',
|
||||||
|
'video-info': '视频统计信息',
|
||||||
},
|
},
|
||||||
'zh-tw': {
|
'zh-tw': {
|
||||||
'Danmaku is loading': '彈幕載入中',
|
'danmaku-loading': '彈幕載入中',
|
||||||
Top: '頂部',
|
top: '頂部',
|
||||||
Bottom: '底部',
|
bottom: '底部',
|
||||||
Rolling: '滾動',
|
rolling: '滾動',
|
||||||
'Input danmaku, hit Enter': '輸入彈幕,Enter 發送',
|
'input-danmaku-enter': '輸入彈幕,Enter 發送',
|
||||||
'About author': '關於作者',
|
'about-author': '關於作者',
|
||||||
'DPlayer feedback': '播放器意見回饋',
|
'dplayer-feedback': '播放器意見回饋',
|
||||||
'About DPlayer': '關於 DPlayer 播放器',
|
'about-dplayer': '關於 DPlayer 播放器',
|
||||||
Loop: '循環播放',
|
loop: '循環播放',
|
||||||
Speed: '速度',
|
speed: '速度',
|
||||||
'Opacity for danmaku': '彈幕透明度',
|
'opacity-danmaku': '彈幕透明度',
|
||||||
Normal: '正常',
|
normal: '正常',
|
||||||
'Please input danmaku content!': '請輸入彈幕內容啊!',
|
'please-input-danmaku': '請輸入彈幕內容啊!',
|
||||||
'Set danmaku color': '設定彈幕顏色',
|
'set-danmaku-color': '設定彈幕顏色',
|
||||||
'Set danmaku type': '設定彈幕類型',
|
'set-danmaku-type': '設定彈幕類型',
|
||||||
'Show danmaku': '顯示彈幕',
|
'show-danmaku': '顯示彈幕',
|
||||||
'Video load failed': '影片載入失敗',
|
'video-failed': '影片載入失敗',
|
||||||
'Danmaku load failed': '彈幕載入失敗',
|
'danmaku-failed': '彈幕載入失敗',
|
||||||
'Danmaku send failed': '彈幕發送失敗',
|
'danmaku-send-failed': '彈幕發送失敗',
|
||||||
'Switching to': '正在切換至',
|
'switching-quality': '正在切換至 %q 畫質',
|
||||||
'Switched to': '已經切換至',
|
'switched-quality': '已經切換至 %q 畫質',
|
||||||
quality: '畫質',
|
ff: '快進 %s 秒',
|
||||||
FF: '快進',
|
rew: '快退 %s 秒',
|
||||||
REW: '快退',
|
'unlimited-danmaku': '巨量彈幕',
|
||||||
'Unlimited danmaku': '巨量彈幕',
|
'send-danmaku': '發送彈幕',
|
||||||
'Send danmaku': '發送彈幕',
|
setting: '設定',
|
||||||
Setting: '設定',
|
fullscreen: '全螢幕',
|
||||||
'Full screen': '全螢幕',
|
'web-fullscreen': '頁面全螢幕',
|
||||||
'Web full screen': '頁面全螢幕',
|
send: '發送',
|
||||||
Send: '發送',
|
screenshot: '截圖',
|
||||||
Screenshot: '截圖',
|
airplay: '無線投屏',
|
||||||
AirPlay: '無線投屏',
|
chromecast: 'ChromeCast',
|
||||||
s: '秒',
|
subtitle: '字幕',
|
||||||
'Show subtitle': '顯示字幕',
|
off: '關閉',
|
||||||
'Hide subtitle': '隱藏字幕',
|
'show-subs': '顯示字幕',
|
||||||
Volume: '音量',
|
'hide-subs': '隱藏字幕',
|
||||||
Live: '直播',
|
volume: '音量',
|
||||||
'Video info': '影片統計訊息',
|
live: '直播',
|
||||||
|
'video-info': '影片統計訊息',
|
||||||
|
},
|
||||||
|
'ko-kr': {
|
||||||
|
'danmaku-loading': 'Danmaku를 불러오는 중입니다.',
|
||||||
|
top: 'Top',
|
||||||
|
bottom: 'Bottom',
|
||||||
|
rolling: 'Rolling',
|
||||||
|
'input-danmaku-enter': 'Danmaku를 입력하고 Enter를 누르세요.',
|
||||||
|
'about-author': '만든이',
|
||||||
|
'dplayer-feedback': '피드백 보내기',
|
||||||
|
'about-dplayer': 'DPlayer 정보',
|
||||||
|
loop: '반복',
|
||||||
|
speed: '배속',
|
||||||
|
'opacity-danmaku': 'Danmaku 불투명도',
|
||||||
|
normal: '표준',
|
||||||
|
'please-input-danmaku': 'Danmaku를 입력하세요!',
|
||||||
|
'set-danmaku-color': 'Danmaku 색상',
|
||||||
|
'set-danmaku-type': 'Danmaku 설정',
|
||||||
|
'show-danmaku': 'Danmaku 표시',
|
||||||
|
'video-failed': '비디오를 불러오지 못했습니다.',
|
||||||
|
'danmaku-failed': 'Danmaku를 불러오지 못했습니다.',
|
||||||
|
'danmaku-send-failed': 'Danmaku 전송에 실패했습니다.',
|
||||||
|
'Switching to': '',
|
||||||
|
'Switched to': '',
|
||||||
|
'switching-quality': '전환 %q 화질',
|
||||||
|
'switched-quality': '전환 됨 %q 화질',
|
||||||
|
ff: '앞으로 %s 초',
|
||||||
|
rew: '뒤로 %s 초',
|
||||||
|
'unlimited-danmaku': '끝없는 Danmaku',
|
||||||
|
'send-danmaku': 'Danmaku 보내기',
|
||||||
|
setting: '설정',
|
||||||
|
fullscreen: '전체 화면',
|
||||||
|
'web-fullscreen': '웹 내 전체화면',
|
||||||
|
send: '보내기',
|
||||||
|
screenshot: '화면 캡쳐',
|
||||||
|
airplay: '에어플레이',
|
||||||
|
chromecast: 'ChromeCast',
|
||||||
|
subtitle: '부제',
|
||||||
|
off: '끄다',
|
||||||
|
'show-subs': '자막 보이기',
|
||||||
|
'hide-subs': '자막 숨기기',
|
||||||
|
Volume: '볼륨',
|
||||||
|
live: '생방송',
|
||||||
|
'video-info': '비디오 정보',
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
'danmaku-loading': 'Danmaku lädt...',
|
||||||
|
top: 'Oben',
|
||||||
|
bottom: 'Unten',
|
||||||
|
rolling: 'Rollend',
|
||||||
|
'input-danmaku-enter': 'Drücke Enter nach dem Einfügen vom Danmaku',
|
||||||
|
'about-author': 'Über den Autor',
|
||||||
|
'dplayer-feedback': 'DPlayer Feedback',
|
||||||
|
'about-dplayer': 'Über DPlayer',
|
||||||
|
loop: 'Wiederholen',
|
||||||
|
speed: 'Geschwindigkeit',
|
||||||
|
'opacity-danmaku': 'Transparenz für Danmaku',
|
||||||
|
normal: 'Normal',
|
||||||
|
'please-input-danmaku': 'Bitte Danmaku Inhalt eingeben!',
|
||||||
|
'set-danmaku-color': 'Danmaku Farbe festlegen',
|
||||||
|
'set-danmaku-type': 'Danmaku Typ festlegen',
|
||||||
|
'show-danmaku': 'Zeige Danmaku',
|
||||||
|
'video-failed': 'Das Video konnte nicht geladen werden',
|
||||||
|
'danmaku-failed': 'Danmaku konnte nicht geladen werden',
|
||||||
|
'danmaku-send-failed': 'Das senden von Danmaku ist fehgeschlagen',
|
||||||
|
'switching-quality': 'Wechsle zur %q Qualität',
|
||||||
|
'switched-quality': 'Zur %q Qualität gewechselt',
|
||||||
|
ff: '%s s Vorwärts',
|
||||||
|
rew: '%s s Zurück',
|
||||||
|
'unlimited-danmaku': 'Unlimitiertes Danmaku',
|
||||||
|
'send-danmaku': 'Sende Danmaku',
|
||||||
|
setting: 'Einstellungen',
|
||||||
|
fullscreen: 'Vollbild',
|
||||||
|
'web-fullscreen': 'Browser Vollbild',
|
||||||
|
send: 'Senden',
|
||||||
|
screenshot: 'Screenshot',
|
||||||
|
airplay: 'AirPlay',
|
||||||
|
'show-subs': 'Zeige Untertitel',
|
||||||
|
chromecast: 'ChromeCast',
|
||||||
|
subtitle: 'Untertitel',
|
||||||
|
off: 'Schließung',
|
||||||
|
'hide-subs': 'Verstecke Untertitel',
|
||||||
|
volume: 'Lautstärke',
|
||||||
|
live: 'Live',
|
||||||
|
'video-info': 'Video Info',
|
||||||
|
},
|
||||||
|
"ja":{
|
||||||
|
'danmaku-loading':'コメントを読み込んでいます',
|
||||||
|
top:'トップ',
|
||||||
|
bottom:'ボトム',
|
||||||
|
rolling:'スクロール',
|
||||||
|
'input-danmaku-enter':'コメントを入力し,Enter で送信',
|
||||||
|
'about-author':'作者について',
|
||||||
|
'dplayer-feedback':'DPlayer についての意見・要望',
|
||||||
|
'about-dplayer':'DPlayer について',
|
||||||
|
loop:'くり返し',
|
||||||
|
speed:'再生速度',
|
||||||
|
'opacity-danmaku':'コメントの透明度',
|
||||||
|
normal:'通常',
|
||||||
|
'please-input-danmaku':'コメントを入力してください!',
|
||||||
|
'set-danmaku-color':'コメントの色',
|
||||||
|
'set-danmaku-type':'コメントの種類',
|
||||||
|
'show-danmaku':'コメント表示',
|
||||||
|
'video-failed':'ビデオの読み込みに失敗',
|
||||||
|
'danmaku-failed':'コメントの読み込みに失敗',
|
||||||
|
'danmaku-send-failed':'コメントの送信に失敗',
|
||||||
|
'switching-quality':'%qへ切り替え中',
|
||||||
|
'switched-quality':'%qへ切り替え完了',
|
||||||
|
quality:'へ',
|
||||||
|
ff:'%s 秒早送り',
|
||||||
|
rew:'%s 秒早戻し',
|
||||||
|
'unlimited-danmaku':'コメント無制限',
|
||||||
|
'send-danmaku':'コメント送信',
|
||||||
|
setting:'設定',
|
||||||
|
fullscreen:'全画面表示',
|
||||||
|
'web-fullscreen':'ブラウザ全体表示',
|
||||||
|
send:'送信',
|
||||||
|
screenshot:'画面コピー',
|
||||||
|
airplay:'AirPlay',
|
||||||
|
'show-subs':'字幕表示',
|
||||||
|
chromecast: 'ChromeCast',
|
||||||
|
subtitle: '字幕',
|
||||||
|
off: 'OFF',
|
||||||
|
'hide-subs':'字幕非表示',
|
||||||
|
volume:'音量',
|
||||||
|
live:'ライブ',
|
||||||
|
'video-info':'動画情報'
|
||||||
|
},
|
||||||
|
'ru': {
|
||||||
|
'danmaku-loading': 'Загрузка комментариев',
|
||||||
|
top: 'Вверху',
|
||||||
|
bottom: 'Внизу',
|
||||||
|
rolling: 'Лента',
|
||||||
|
'input-danmaku-enter': 'Введите комментарий, нажмите Enter',
|
||||||
|
'about-author': 'Об авторе',
|
||||||
|
'dplayer-feedback': 'Обратная связь',
|
||||||
|
'about-dplayer': 'О плеере',
|
||||||
|
loop: 'Закольцевать',
|
||||||
|
speed: 'Скорость',
|
||||||
|
'opacity-danmaku': 'Прозрачность',
|
||||||
|
normal: 'Обычный',
|
||||||
|
'please-input-danmaku': 'Пожалуйста, введите комментарий!',
|
||||||
|
'set-danmaku-color': 'Цвет комментария',
|
||||||
|
'set-danmaku-type': 'Тип комментария',
|
||||||
|
'show-danmaku': 'Показать комментарии',
|
||||||
|
'video-failed': 'Ошибка загрузки видео',
|
||||||
|
'danmaku-failed': 'Ошибка загрузки комментариев',
|
||||||
|
'danmaku-send-failed': 'Ошибка отправки комментария',
|
||||||
|
'switching-quality': 'Переключение качества на: %q',
|
||||||
|
'switched-quality': 'Установлено качество: %q',
|
||||||
|
ff: 'Вперёд: %s с',
|
||||||
|
rew: 'Назад: %s с',
|
||||||
|
'unlimited-danmaku': 'Без ограничений',
|
||||||
|
'send-danmaku': 'Отправить комментарий',
|
||||||
|
setting: 'Настройки',
|
||||||
|
fullscreen: 'На весь экран',
|
||||||
|
'web-fullscreen': 'На весь Web экран',
|
||||||
|
send: 'Отправить',
|
||||||
|
screenshot: 'Скриншот',
|
||||||
|
airplay: 'AirPlay',
|
||||||
|
chromecast: 'ChromeCast',
|
||||||
|
subtitle: 'Комментарий',
|
||||||
|
off: 'Выкл',
|
||||||
|
'show-subs': 'Показать комментарии',
|
||||||
|
'hide-subs': 'Скрыть комментарии',
|
||||||
|
volume: 'Громкость',
|
||||||
|
live: 'Живые комментарии',
|
||||||
|
'video-info': 'Информация о видео',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default i18n;
|
export { i18n };
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import camera from '../assets/camera.svg';
|
||||||
import airplay from '../assets/airplay.svg';
|
import airplay from '../assets/airplay.svg';
|
||||||
import subtitle from '../assets/subtitle.svg';
|
import subtitle from '../assets/subtitle.svg';
|
||||||
import loading from '../assets/loading.svg';
|
import loading from '../assets/loading.svg';
|
||||||
|
import chromecast from '../assets/chromecast.svg';
|
||||||
|
|
||||||
const Icons = {
|
const Icons = {
|
||||||
play: play,
|
play: play,
|
||||||
|
|
@ -34,6 +35,7 @@ const Icons = {
|
||||||
subtitle: subtitle,
|
subtitle: subtitle,
|
||||||
loading: loading,
|
loading: loading,
|
||||||
airplay: airplay,
|
airplay: airplay,
|
||||||
|
chromecast: chromecast,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Icons;
|
export default Icons;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import '../css/index.scss';
|
import '../css/index.less';
|
||||||
import DPlayer from './player';
|
import DPlayer from './player';
|
||||||
|
|
||||||
/* global DPLAYER_VERSION GIT_HASH */
|
/* global DPLAYER_VERSION GIT_HASH */
|
||||||
console.log(`${'\n'} %c DPlayer v${DPLAYER_VERSION} ${GIT_HASH} %c http://dplayer.js.org ${'\n'}${'\n'}`, 'color: #fadfa3; background: #030307; padding:5px 0;', 'background: #fadfa3; padding:5px 0;');
|
console.log(`${'\n'} %c DPlayer v${DPLAYER_VERSION} ${GIT_HASH} %c https://dplayer.diygod.dev ${'\n'}${'\n'}`, 'color: #fadfa3; background: #030307; padding:5px 0;', 'background: #fadfa3; padding:5px 0;');
|
||||||
|
|
||||||
export default DPlayer;
|
export default DPlayer;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export default (options) => {
|
||||||
lang: (navigator.language || navigator.browserLanguage).toLowerCase(),
|
lang: (navigator.language || navigator.browserLanguage).toLowerCase(),
|
||||||
screenshot: false,
|
screenshot: false,
|
||||||
airplay: true,
|
airplay: true,
|
||||||
|
chromecast: false,
|
||||||
hotkey: true,
|
hotkey: true,
|
||||||
preload: 'metadata',
|
preload: 'metadata',
|
||||||
volume: 0.7,
|
volume: 0.7,
|
||||||
|
|
@ -21,6 +22,7 @@ export default (options) => {
|
||||||
contextmenu: [],
|
contextmenu: [],
|
||||||
mutex: true,
|
mutex: true,
|
||||||
pluginOptions: { hls: {}, flv: {}, dash: {}, webtorrent: {} },
|
pluginOptions: { hls: {}, flv: {}, dash: {}, webtorrent: {} },
|
||||||
|
preventClickToggle: false,
|
||||||
};
|
};
|
||||||
for (const defaultKey in defaultOption) {
|
for (const defaultKey in defaultOption) {
|
||||||
if (defaultOption.hasOwnProperty(defaultKey) && !options.hasOwnProperty(defaultKey)) {
|
if (defaultOption.hasOwnProperty(defaultKey) && !options.hasOwnProperty(defaultKey)) {
|
||||||
|
|
@ -50,13 +52,13 @@ export default (options) => {
|
||||||
|
|
||||||
options.contextmenu = options.contextmenu.concat([
|
options.contextmenu = options.contextmenu.concat([
|
||||||
{
|
{
|
||||||
text: 'Video info',
|
key: 'video-info',
|
||||||
click: (player) => {
|
click: (player) => {
|
||||||
player.infoPanel.triggle();
|
player.infoPanel.triggle();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'About author',
|
key: 'about-author',
|
||||||
link: 'https://diygod.me',
|
link: 'https://diygod.me',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
195
src/js/player.js
195
src/js/player.js
|
|
@ -2,7 +2,7 @@ import Promise from 'promise-polyfill';
|
||||||
|
|
||||||
import utils from './utils';
|
import utils from './utils';
|
||||||
import handleOption from './options';
|
import handleOption from './options';
|
||||||
import i18n from './i18n';
|
import { i18n } from './i18n';
|
||||||
import Template from './template';
|
import Template from './template';
|
||||||
import Icons from './icons';
|
import Icons from './icons';
|
||||||
import Danmaku from './danmaku';
|
import Danmaku from './danmaku';
|
||||||
|
|
@ -10,6 +10,7 @@ import Events from './events';
|
||||||
import FullScreen from './fullscreen';
|
import FullScreen from './fullscreen';
|
||||||
import User from './user';
|
import User from './user';
|
||||||
import Subtitle from './subtitle';
|
import Subtitle from './subtitle';
|
||||||
|
import Subtitles from './subtitles';
|
||||||
import Bar from './bar';
|
import Bar from './bar';
|
||||||
import Timer from './timer';
|
import Timer from './timer';
|
||||||
import Bezel from './bezel';
|
import Bezel from './bezel';
|
||||||
|
|
@ -42,6 +43,7 @@ class DPlayer {
|
||||||
this.events = new Events();
|
this.events = new Events();
|
||||||
this.user = new User(this);
|
this.user = new User(this);
|
||||||
this.container = this.options.container;
|
this.container = this.options.container;
|
||||||
|
this.noticeList = {};
|
||||||
|
|
||||||
this.container.classList.add('dplayer');
|
this.container.classList.add('dplayer');
|
||||||
if (!this.options.danmaku) {
|
if (!this.options.danmaku) {
|
||||||
|
|
@ -49,6 +51,8 @@ class DPlayer {
|
||||||
}
|
}
|
||||||
if (this.options.live) {
|
if (this.options.live) {
|
||||||
this.container.classList.add('dplayer-live');
|
this.container.classList.add('dplayer-live');
|
||||||
|
} else {
|
||||||
|
this.container.classList.remove('dplayer-live');
|
||||||
}
|
}
|
||||||
if (utils.isMobile) {
|
if (utils.isMobile) {
|
||||||
this.container.classList.add('dplayer-mobile');
|
this.container.classList.add('dplayer-mobile');
|
||||||
|
|
@ -58,6 +62,43 @@ class DPlayer {
|
||||||
this.container.classList.add('dplayer-arrow');
|
this.container.classList.add('dplayer-arrow');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// multi subtitles defaultSubtitle add index, off option
|
||||||
|
if (this.options.subtitle) {
|
||||||
|
if (Array.isArray(this.options.subtitle.url)) {
|
||||||
|
const offSubtitle = {
|
||||||
|
subtitle: '',
|
||||||
|
lang: 'off',
|
||||||
|
};
|
||||||
|
this.options.subtitle.url.push(offSubtitle);
|
||||||
|
if (this.options.subtitle.defaultSubtitle) {
|
||||||
|
if (typeof this.options.subtitle.defaultSubtitle === 'string') {
|
||||||
|
// defaultSubtitle is string, match in lang then name.
|
||||||
|
this.options.subtitle.index = this.options.subtitle.url.findIndex((sub) =>
|
||||||
|
/* if (sub.lang === this.options.subtitle.defaultSubtitle) {
|
||||||
|
return true;
|
||||||
|
} else if (sub.name === this.options.subtitle.defaultSubtitle) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
} */
|
||||||
|
sub.lang === this.options.subtitle.defaultSubtitle ? true : sub.name === this.options.subtitle.defaultSubtitle ? true : false
|
||||||
|
);
|
||||||
|
} else if (typeof this.options.subtitle.defaultSubtitle === 'number') {
|
||||||
|
// defaultSubtitle is int, directly use for index
|
||||||
|
this.options.subtitle.index = this.options.subtitle.defaultSubtitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// defaultSubtitle not match or not exist or index bound(when defaultSubtitle is int), try browser language.
|
||||||
|
if (this.options.subtitle.index === -1 || !this.options.subtitle.index || this.options.subtitle.index > this.options.subtitle.url.length - 1) {
|
||||||
|
this.options.subtitle.index = this.options.subtitle.url.findIndex((sub) => sub.lang === this.options.lang);
|
||||||
|
}
|
||||||
|
// browser language not match, default off title
|
||||||
|
if (this.options.subtitle.index === -1) {
|
||||||
|
this.options.subtitle.index = this.options.subtitle.url.length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.template = new Template({
|
this.template = new Template({
|
||||||
container: this.container,
|
container: this.container,
|
||||||
options: this.options,
|
options: this.options,
|
||||||
|
|
@ -77,6 +118,7 @@ class DPlayer {
|
||||||
|
|
||||||
if (this.options.danmaku) {
|
if (this.options.danmaku) {
|
||||||
this.danmaku = new Danmaku({
|
this.danmaku = new Danmaku({
|
||||||
|
player: this,
|
||||||
container: this.template.danmaku,
|
container: this.template.danmaku,
|
||||||
opacity: this.user.get('opacity'),
|
opacity: this.user.get('opacity'),
|
||||||
callback: () => {
|
callback: () => {
|
||||||
|
|
@ -104,6 +146,7 @@ class DPlayer {
|
||||||
maximum: this.options.danmaku.maximum,
|
maximum: this.options.danmaku.maximum,
|
||||||
addition: this.options.danmaku.addition,
|
addition: this.options.danmaku.addition,
|
||||||
user: this.options.danmaku.user,
|
user: this.options.danmaku.user,
|
||||||
|
speedRate: this.options.danmaku.speedRate,
|
||||||
},
|
},
|
||||||
events: this.events,
|
events: this.events,
|
||||||
tran: (msg) => this.tran(msg),
|
tran: (msg) => this.tran(msg),
|
||||||
|
|
@ -114,21 +157,14 @@ class DPlayer {
|
||||||
|
|
||||||
this.setting = new Setting(this);
|
this.setting = new Setting(this);
|
||||||
this.plugins = {};
|
this.plugins = {};
|
||||||
|
this.docClickFun = () => {
|
||||||
document.addEventListener(
|
this.focus = false;
|
||||||
'click',
|
};
|
||||||
() => {
|
this.containerClickFun = () => {
|
||||||
this.focus = false;
|
this.focus = true;
|
||||||
},
|
};
|
||||||
true
|
document.addEventListener('click', this.docClickFun, true);
|
||||||
);
|
this.container.addEventListener('click', this.containerClickFun, true);
|
||||||
this.container.addEventListener(
|
|
||||||
'click',
|
|
||||||
() => {
|
|
||||||
this.focus = true;
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
this.paused = true;
|
this.paused = true;
|
||||||
|
|
||||||
|
|
@ -146,6 +182,8 @@ class DPlayer {
|
||||||
this.play();
|
this.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.moveBar = false;
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
instances.push(this);
|
instances.push(this);
|
||||||
}
|
}
|
||||||
|
|
@ -159,9 +197,9 @@ class DPlayer {
|
||||||
time = Math.min(time, this.video.duration);
|
time = Math.min(time, this.video.duration);
|
||||||
}
|
}
|
||||||
if (this.video.currentTime < time) {
|
if (this.video.currentTime < time) {
|
||||||
this.notice(`${this.tran('FF')} ${(time - this.video.currentTime).toFixed(0)} ${this.tran('s')}`);
|
this.notice(`${this.tran('ff').replace('%s', (time - this.video.currentTime).toFixed(0))}`);
|
||||||
} else if (this.video.currentTime > time) {
|
} else if (this.video.currentTime > time) {
|
||||||
this.notice(`${this.tran('REW')} ${(this.video.currentTime - time).toFixed(0)} ${this.tran('s')}`);
|
this.notice(`${this.tran('rew').replace('%s', (this.video.currentTime - time).toFixed(0))}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.video.currentTime = time;
|
this.video.currentTime = time;
|
||||||
|
|
@ -258,7 +296,7 @@ class DPlayer {
|
||||||
this.user.set('volume', percentage);
|
this.user.set('volume', percentage);
|
||||||
}
|
}
|
||||||
if (!nonotice) {
|
if (!nonotice) {
|
||||||
this.notice(`${this.tran('Volume')} ${(percentage * 100).toFixed(0)}%`);
|
this.notice(`${this.tran('volume')} ${(percentage * 100).toFixed(0)}%`, undefined, undefined, 'volume');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.video.volume = percentage;
|
this.video.volume = percentage;
|
||||||
|
|
@ -344,6 +382,7 @@ class DPlayer {
|
||||||
this.type = 'normal';
|
this.type = 'normal';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const src = this.quality.url; // 真实的视频 url, 用于切换清晰度时销毁实例
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
// https://github.com/video-dev/hls.js
|
// https://github.com/video-dev/hls.js
|
||||||
case 'hls':
|
case 'hls':
|
||||||
|
|
@ -358,6 +397,12 @@ class DPlayer {
|
||||||
hls.destroy();
|
hls.destroy();
|
||||||
delete this.plugins.hls;
|
delete this.plugins.hls;
|
||||||
});
|
});
|
||||||
|
// 切换清晰度时销毁实例
|
||||||
|
this.events.on('quality_end', () => {
|
||||||
|
if (src !== this.quality.url) {
|
||||||
|
hls.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.notice('Error: Hls is not supported.');
|
this.notice('Error: Hls is not supported.');
|
||||||
}
|
}
|
||||||
|
|
@ -386,6 +431,14 @@ class DPlayer {
|
||||||
flvPlayer.destroy();
|
flvPlayer.destroy();
|
||||||
delete this.plugins.flvjs;
|
delete this.plugins.flvjs;
|
||||||
});
|
});
|
||||||
|
// 切换清晰度时销毁实例
|
||||||
|
this.events.on('quality_end', () => {
|
||||||
|
if (src !== this.quality.url) {
|
||||||
|
flvPlayer.unload();
|
||||||
|
flvPlayer.detachMediaElement();
|
||||||
|
flvPlayer.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.notice('Error: flvjs is not supported.');
|
this.notice('Error: flvjs is not supported.');
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +450,8 @@ class DPlayer {
|
||||||
// https://github.com/Dash-Industry-Forum/dash.js
|
// https://github.com/Dash-Industry-Forum/dash.js
|
||||||
case 'dash':
|
case 'dash':
|
||||||
if (window.dashjs) {
|
if (window.dashjs) {
|
||||||
const dashjsPlayer = window.dashjs.MediaPlayer().create().initialize(video, video.src, false);
|
const dashjsPlayer = window.dashjs.MediaPlayer().create();
|
||||||
|
dashjsPlayer.initialize(video, video.src, false, 0);
|
||||||
const options = this.options.pluginOptions.dash;
|
const options = this.options.pluginOptions.dash;
|
||||||
dashjsPlayer.updateSettings(options);
|
dashjsPlayer.updateSettings(options);
|
||||||
this.plugins.dash = dashjsPlayer;
|
this.plugins.dash = dashjsPlayer;
|
||||||
|
|
@ -405,6 +459,12 @@ class DPlayer {
|
||||||
window.dashjs.MediaPlayer().reset();
|
window.dashjs.MediaPlayer().reset();
|
||||||
delete this.plugins.dash;
|
delete this.plugins.dash;
|
||||||
});
|
});
|
||||||
|
// 切换清晰度时销毁实例
|
||||||
|
this.events.on('quality_end', () => {
|
||||||
|
if (src !== this.quality.url) {
|
||||||
|
window.dashjs.MediaPlayer().reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.notice("Error: Can't find dashjs.");
|
this.notice("Error: Can't find dashjs.");
|
||||||
}
|
}
|
||||||
|
|
@ -434,6 +494,13 @@ class DPlayer {
|
||||||
client.destroy();
|
client.destroy();
|
||||||
delete this.plugins.webtorrent;
|
delete this.plugins.webtorrent;
|
||||||
});
|
});
|
||||||
|
// 切换清晰度时销毁实例
|
||||||
|
this.events.on('quality_end', () => {
|
||||||
|
if (src !== this.quality.url) {
|
||||||
|
client.remove(torrentId);
|
||||||
|
client.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.notice('Error: Webtorrent is not supported.');
|
this.notice('Error: Webtorrent is not supported.');
|
||||||
}
|
}
|
||||||
|
|
@ -471,7 +538,7 @@ class DPlayer {
|
||||||
// Not a video load error, may be poster load failed, see #307
|
// Not a video load error, may be poster load failed, see #307
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.tran && this.notice && this.type !== 'webtorrent' && this.notice(this.tran('Video load failed'), -1);
|
this.tran && this.notice && this.type !== 'webtorrent' && this.notice(this.tran('video-failed'));
|
||||||
});
|
});
|
||||||
|
|
||||||
// video end
|
// video end
|
||||||
|
|
@ -501,7 +568,9 @@ class DPlayer {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('timeupdate', () => {
|
this.on('timeupdate', () => {
|
||||||
this.bar.set('played', this.video.currentTime / this.video.duration, 'width');
|
if (!this.moveBar) {
|
||||||
|
this.bar.set('played', this.video.currentTime / this.video.duration, 'width');
|
||||||
|
}
|
||||||
const currentTime = utils.secondToTime(this.video.currentTime);
|
const currentTime = utils.secondToTime(this.video.currentTime);
|
||||||
if (this.template.ptime.innerHTML !== currentTime) {
|
if (this.template.ptime.innerHTML !== currentTime) {
|
||||||
this.template.ptime.innerHTML = currentTime;
|
this.template.ptime.innerHTML = currentTime;
|
||||||
|
|
@ -509,15 +578,20 @@ class DPlayer {
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < this.events.videoEvents.length; i++) {
|
for (let i = 0; i < this.events.videoEvents.length; i++) {
|
||||||
video.addEventListener(this.events.videoEvents[i], () => {
|
video.addEventListener(this.events.videoEvents[i], (e) => {
|
||||||
this.events.trigger(this.events.videoEvents[i]);
|
this.events.trigger(this.events.videoEvents[i], e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.volume(this.user.get('volume'), true, true);
|
this.volume(this.user.get('volume'), true, true);
|
||||||
|
|
||||||
if (this.options.subtitle) {
|
if (this.options.subtitle) {
|
||||||
|
// init old single subtitle function(sub show and style)
|
||||||
this.subtitle = new Subtitle(this.template.subtitle, this.video, this.options.subtitle, this.events);
|
this.subtitle = new Subtitle(this.template.subtitle, this.video, this.options.subtitle, this.events);
|
||||||
|
// init multi subtitles function(sub update)
|
||||||
|
if (Array.isArray(this.options.subtitle.url)) {
|
||||||
|
this.subtitles = new Subtitles(this);
|
||||||
|
}
|
||||||
if (!this.user.get('subtitle')) {
|
if (!this.user.get('subtitle')) {
|
||||||
this.subtitle.hide();
|
this.subtitle.hide();
|
||||||
}
|
}
|
||||||
|
|
@ -529,6 +603,7 @@ class DPlayer {
|
||||||
if (this.qualityIndex === index || this.switchingQuality) {
|
if (this.qualityIndex === index || this.switchingQuality) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
this.prevIndex = this.qualityIndex;
|
||||||
this.qualityIndex = index;
|
this.qualityIndex = index;
|
||||||
}
|
}
|
||||||
this.switchingQuality = true;
|
this.switchingQuality = true;
|
||||||
|
|
@ -551,7 +626,7 @@ class DPlayer {
|
||||||
this.video = videoEle;
|
this.video = videoEle;
|
||||||
this.initVideo(this.video, this.quality.type || this.options.video.type);
|
this.initVideo(this.video, this.quality.type || this.options.video.type);
|
||||||
this.seek(this.prevVideo.currentTime);
|
this.seek(this.prevVideo.currentTime);
|
||||||
this.notice(`${this.tran('Switching to')} ${this.quality.name} ${this.tran('quality')}`, -1);
|
this.notice(`${this.tran('switching-quality').replace('%q', this.quality.name)}`, -1, undefined, 'switch-quality');
|
||||||
this.events.trigger('quality_start', this.quality);
|
this.events.trigger('quality_start', this.quality);
|
||||||
|
|
||||||
this.on('canplay', () => {
|
this.on('canplay', () => {
|
||||||
|
|
@ -566,26 +641,69 @@ class DPlayer {
|
||||||
this.video.play();
|
this.video.play();
|
||||||
}
|
}
|
||||||
this.prevVideo = null;
|
this.prevVideo = null;
|
||||||
this.notice(`${this.tran('Switched to')} ${this.quality.name} ${this.tran('quality')}`);
|
this.notice(`${this.tran('switched-quality').replace('%q', this.quality.name)}`, undefined, undefined, 'switch-quality');
|
||||||
this.switchingQuality = false;
|
this.switchingQuality = false;
|
||||||
|
|
||||||
this.events.trigger('quality_end');
|
this.events.trigger('quality_end');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.on('error', () => {
|
||||||
|
if (!this.video.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.prevVideo) {
|
||||||
|
this.template.videoWrap.removeChild(this.video);
|
||||||
|
this.video = this.prevVideo;
|
||||||
|
if (!paused) {
|
||||||
|
this.video.play();
|
||||||
|
}
|
||||||
|
this.qualityIndex = this.prevIndex;
|
||||||
|
this.quality = this.options.video.quality[this.qualityIndex];
|
||||||
|
this.noticeTime = setTimeout(() => {
|
||||||
|
this.template.notice.style.opacity = 0;
|
||||||
|
this.events.trigger('notice_hide');
|
||||||
|
}, 3000);
|
||||||
|
this.prevVideo = null;
|
||||||
|
this.switchingQuality = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
notice(text, time = 2000, opacity = 0.8) {
|
notice(text, time = 2000, opacity = 0.8, id) {
|
||||||
this.template.notice.innerHTML = text;
|
let oldNoticeEle;
|
||||||
this.template.notice.style.opacity = opacity;
|
if (id) {
|
||||||
if (this.noticeTime) {
|
oldNoticeEle = document.getElementById(`dplayer-notice-${id}`);
|
||||||
clearTimeout(this.noticeTime);
|
if (oldNoticeEle) {
|
||||||
|
oldNoticeEle.innerHTML = text;
|
||||||
|
}
|
||||||
|
if (this.noticeList[id]) {
|
||||||
|
clearTimeout(this.noticeList[id]);
|
||||||
|
this.noticeList[id] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.events.trigger('notice_show', text);
|
if (!oldNoticeEle) {
|
||||||
|
const notice = Template.NewNotice(text, opacity, id);
|
||||||
|
this.template.noticeList.appendChild(notice);
|
||||||
|
oldNoticeEle = notice;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.events.trigger('notice_show', oldNoticeEle);
|
||||||
|
|
||||||
if (time > 0) {
|
if (time > 0) {
|
||||||
this.noticeTime = setTimeout(() => {
|
this.noticeList[id] = setTimeout(
|
||||||
this.template.notice.style.opacity = 0;
|
(function (e, dp) {
|
||||||
this.events.trigger('notice_hide');
|
return () => {
|
||||||
}, time);
|
e.addEventListener('animationend', () => {
|
||||||
|
dp.template.noticeList.removeChild(e);
|
||||||
|
});
|
||||||
|
e.classList.add('remove-notice');
|
||||||
|
dp.events.trigger('notice_hide');
|
||||||
|
dp.noticeList[id] = null;
|
||||||
|
};
|
||||||
|
})(oldNoticeEle, this),
|
||||||
|
time
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -606,6 +724,11 @@ class DPlayer {
|
||||||
destroy() {
|
destroy() {
|
||||||
instances.splice(instances.indexOf(this), 1);
|
instances.splice(instances.indexOf(this), 1);
|
||||||
this.pause();
|
this.pause();
|
||||||
|
document.removeEventListener('click', this.docClickFun, true);
|
||||||
|
this.container.removeEventListener('click', this.containerClickFun, true);
|
||||||
|
this.fullScreen.destroy();
|
||||||
|
this.hotkey.destroy();
|
||||||
|
this.contextmenu.destroy();
|
||||||
this.controller.destroy();
|
this.controller.destroy();
|
||||||
this.timer.destroy();
|
this.timer.destroy();
|
||||||
this.video.src = '';
|
this.video.src = '';
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class Subtitle {
|
||||||
const track = this.video.textTracks[0];
|
const track = this.video.textTracks[0];
|
||||||
|
|
||||||
track.oncuechange = () => {
|
track.oncuechange = () => {
|
||||||
const cue = track.activeCues[0];
|
const cue = track.activeCues[track.activeCues.length - 1];
|
||||||
this.container.innerHTML = '';
|
this.container.innerHTML = '';
|
||||||
if (cue) {
|
if (cue) {
|
||||||
const template = document.createElement('div');
|
const template = document.createElement('div');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
class Subtitles {
|
||||||
|
constructor(player) {
|
||||||
|
this.player = player;
|
||||||
|
|
||||||
|
this.player.template.mask.addEventListener('click', () => {
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
this.player.template.subtitlesButton.addEventListener('click', () => {
|
||||||
|
this.adaptiveHeight();
|
||||||
|
this.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastItemIndex = this.player.template.subtitlesItem.length - 1;
|
||||||
|
for (let i = 0; i < lastItemIndex; i++) {
|
||||||
|
this.player.template.subtitlesItem[i].addEventListener('click', () => {
|
||||||
|
this.hide();
|
||||||
|
if (this.player.options.subtitle.index !== i) {
|
||||||
|
// clear subtitle show for new subtitle don't have now duration time. If don't, will display last subtitle.
|
||||||
|
this.player.template.subtitle.innerHTML = `<p></p>`;
|
||||||
|
// update video track src
|
||||||
|
this.player.template.subtrack.src = this.player.template.subtitlesItem[i].dataset.subtitle;
|
||||||
|
// update options current subindex for reload (such as changeQuality)
|
||||||
|
this.player.options.subtitle.index = i;
|
||||||
|
if (this.player.template.subtitle.classList.contains('dplayer-subtitle-hide')) {
|
||||||
|
this.subContainerShow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.player.template.subtitlesItem[lastItemIndex].addEventListener('click', () => {
|
||||||
|
this.hide();
|
||||||
|
if (this.player.options.subtitle.index !== lastItemIndex) {
|
||||||
|
// clear subtitle show for new subtitle don't have now duration time. If don't, will display last subtitle.
|
||||||
|
this.player.template.subtitle.innerHTML = `<p></p>`;
|
||||||
|
// update video track src
|
||||||
|
this.player.template.subtrack.src = '';
|
||||||
|
// update options current subindex for reload (such as changeQuality)
|
||||||
|
this.player.options.subtitle.index = lastItemIndex;
|
||||||
|
this.subContainerHide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subContainerShow() {
|
||||||
|
this.player.template.subtitle.classList.remove('dplayer-subtitle-hide');
|
||||||
|
this.player.events.trigger('subtitle_show');
|
||||||
|
}
|
||||||
|
|
||||||
|
subContainerHide() {
|
||||||
|
this.player.template.subtitle.classList.add('dplayer-subtitle-hide');
|
||||||
|
this.player.events.trigger('subtitle_hide');
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.player.template.subtitlesBox.classList.remove('dplayer-subtitles-box-open');
|
||||||
|
this.player.template.mask.classList.remove('dplayer-mask-show');
|
||||||
|
this.player.controller.disableAutoHide = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.player.template.subtitlesBox.classList.add('dplayer-subtitles-box-open');
|
||||||
|
this.player.template.mask.classList.add('dplayer-mask-show');
|
||||||
|
this.player.controller.disableAutoHide = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
adaptiveHeight() {
|
||||||
|
const curBoxHeight = this.player.template.subtitlesItem.length * 30 + 14;
|
||||||
|
const stdMaxHeight = this.player.template.videoWrap.offsetHeight * 0.8;
|
||||||
|
if (curBoxHeight >= stdMaxHeight - 50) {
|
||||||
|
this.player.template.subtitlesBox.style.bottom = '8px';
|
||||||
|
this.player.template.subtitlesBox.style['max-height'] = stdMaxHeight - 8 + 'px';
|
||||||
|
} else {
|
||||||
|
this.player.template.subtitlesBox.style.bottom = '50px';
|
||||||
|
this.player.template.subtitlesBox.style['max-height'] = stdMaxHeight - 50 + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Subtitles;
|
||||||
|
|
@ -22,7 +22,8 @@ class Template {
|
||||||
current: true,
|
current: true,
|
||||||
pic: this.options.video.pic,
|
pic: this.options.video.pic,
|
||||||
screenshot: this.options.screenshot,
|
screenshot: this.options.screenshot,
|
||||||
airplay: this.options.airplay,
|
airplay: utils.isSafari && !utils.isChrome ? this.options.airplay : false,
|
||||||
|
chromecast: this.options.chromecast,
|
||||||
preload: this.options.preload,
|
preload: this.options.preload,
|
||||||
url: this.options.video.url,
|
url: this.options.video.url,
|
||||||
subtitle: this.options.subtitle,
|
subtitle: this.options.subtitle,
|
||||||
|
|
@ -80,13 +81,18 @@ class Template {
|
||||||
this.qualityList = this.container.querySelector('.dplayer-quality-list');
|
this.qualityList = this.container.querySelector('.dplayer-quality-list');
|
||||||
this.camareButton = this.container.querySelector('.dplayer-camera-icon');
|
this.camareButton = this.container.querySelector('.dplayer-camera-icon');
|
||||||
this.airplayButton = this.container.querySelector('.dplayer-airplay-icon');
|
this.airplayButton = this.container.querySelector('.dplayer-airplay-icon');
|
||||||
|
this.chromecastButton = this.container.querySelector('.dplayer-chromecast-icon');
|
||||||
this.subtitleButton = this.container.querySelector('.dplayer-subtitle-icon');
|
this.subtitleButton = this.container.querySelector('.dplayer-subtitle-icon');
|
||||||
this.subtitleButtonInner = this.container.querySelector('.dplayer-subtitle-icon .dplayer-icon-content');
|
this.subtitleButtonInner = this.container.querySelector('.dplayer-subtitle-icon .dplayer-icon-content');
|
||||||
|
this.subtitlesButton = this.container.querySelector('.dplayer-subtitles-icon');
|
||||||
|
this.subtitlesBox = this.container.querySelector('.dplayer-subtitles-box');
|
||||||
|
this.subtitlesItem = this.container.querySelectorAll('.dplayer-subtitles-item');
|
||||||
this.subtitle = this.container.querySelector('.dplayer-subtitle');
|
this.subtitle = this.container.querySelector('.dplayer-subtitle');
|
||||||
|
this.subtrack = this.container.querySelector('.dplayer-subtrack');
|
||||||
this.qualityButton = this.container.querySelector('.dplayer-quality-icon');
|
this.qualityButton = this.container.querySelector('.dplayer-quality-icon');
|
||||||
this.barPreview = this.container.querySelector('.dplayer-bar-preview');
|
this.barPreview = this.container.querySelector('.dplayer-bar-preview');
|
||||||
this.barWrap = this.container.querySelector('.dplayer-bar-wrap');
|
this.barWrap = this.container.querySelector('.dplayer-bar-wrap');
|
||||||
this.notice = this.container.querySelector('.dplayer-notice');
|
this.noticeList = this.container.querySelector('.dplayer-notice-list');
|
||||||
this.infoPanel = this.container.querySelector('.dplayer-info-panel');
|
this.infoPanel = this.container.querySelector('.dplayer-info-panel');
|
||||||
this.infoPanelClose = this.container.querySelector('.dplayer-info-panel-close');
|
this.infoPanelClose = this.container.querySelector('.dplayer-info-panel-close');
|
||||||
this.infoVersion = this.container.querySelector('.dplayer-info-panel-item-version .dplayer-info-panel-item-data');
|
this.infoVersion = this.container.querySelector('.dplayer-info-panel-item-version .dplayer-info-panel-item-data');
|
||||||
|
|
@ -99,6 +105,17 @@ class Template {
|
||||||
this.infoDanmakuApi = this.container.querySelector('.dplayer-info-panel-item-danmaku-api .dplayer-info-panel-item-data');
|
this.infoDanmakuApi = this.container.querySelector('.dplayer-info-panel-item-danmaku-api .dplayer-info-panel-item-data');
|
||||||
this.infoDanmakuAmount = this.container.querySelector('.dplayer-info-panel-item-danmaku-amount .dplayer-info-panel-item-data');
|
this.infoDanmakuAmount = this.container.querySelector('.dplayer-info-panel-item-danmaku-amount .dplayer-info-panel-item-data');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NewNotice(text, opacity, id) {
|
||||||
|
const notice = document.createElement('div');
|
||||||
|
notice.classList.add('dplayer-notice');
|
||||||
|
notice.style.opacity = opacity;
|
||||||
|
notice.innerText = text;
|
||||||
|
if (id) {
|
||||||
|
notice.id = `dplayer-notice-${id}`;
|
||||||
|
}
|
||||||
|
return notice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Template;
|
export default Template;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ class Timer {
|
||||||
window.mozRequestAnimationFrame ||
|
window.mozRequestAnimationFrame ||
|
||||||
window.oRequestAnimationFrame ||
|
window.oRequestAnimationFrame ||
|
||||||
window.msRequestAnimationFrame ||
|
window.msRequestAnimationFrame ||
|
||||||
function(callback) {
|
function (callback) {
|
||||||
window.setTimeout(callback, 1000 / 60);
|
window.setTimeout(callback, 1000 / 60);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
const isMobile = /mobile/i.test(window.navigator.userAgent);
|
const isMobile = /mobile|android|iphone|ipod|phone|ipad/i.test(window.navigator.userAgent);
|
||||||
|
|
||||||
const isSafari = /Safari/i.test(window.navigator.userAgent);
|
|
||||||
|
|
||||||
const utils = {
|
const utils = {
|
||||||
/**
|
/**
|
||||||
|
|
@ -91,12 +89,12 @@ const utils = {
|
||||||
|
|
||||||
isMobile: isMobile,
|
isMobile: isMobile,
|
||||||
|
|
||||||
isSafari: isSafari,
|
|
||||||
|
|
||||||
isFirefox: /firefox/i.test(window.navigator.userAgent),
|
isFirefox: /firefox/i.test(window.navigator.userAgent),
|
||||||
|
|
||||||
isChrome: /chrome/i.test(window.navigator.userAgent),
|
isChrome: /chrome/i.test(window.navigator.userAgent),
|
||||||
|
|
||||||
|
isSafari: /safari/i.test(window.navigator.userAgent),
|
||||||
|
|
||||||
storage: {
|
storage: {
|
||||||
set: (key, value) => {
|
set: (key, value) => {
|
||||||
localStorage.setItem(key, value);
|
localStorage.setItem(key, value);
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,14 @@
|
||||||
<img src="{{ options.logo }}">
|
<img src="{{ options.logo }}">
|
||||||
</div>
|
</div>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
<div class="dplayer-danmaku"{{ if options.danmaku && options.danmaku.bottm }} style="margin-bottom:{{ options.danmaku.bottm }}"{{ /if }}>
|
<div class="dplayer-danmaku"{{ if options.danmaku && options.danmaku.bottom }} style="margin-bottom:{{ options.danmaku.bottom }}"{{ /if }}>
|
||||||
<div class="dplayer-danmaku-item dplayer-danmaku-item--demo"></div>
|
<div class="dplayer-danmaku-item dplayer-danmaku-item--demo"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-subtitle"></div>
|
<div class="dplayer-subtitle"></div>
|
||||||
<div class="dplayer-bezel">
|
<div class="dplayer-bezel">
|
||||||
<span class="dplayer-bezel-icon"></span>
|
<span class="dplayer-bezel-icon"></span>
|
||||||
{{ if options.danmaku }}
|
{{ if options.danmaku }}
|
||||||
<span class="dplayer-danloading">{{ tran('Danmaku is loading') }}</span>
|
<span class="dplayer-danloading">{{ tran('danmaku-loading') }}</span>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
<span class="diplayer-loading-icon">{{@ icons.loading }}</span>
|
<span class="diplayer-loading-icon">{{@ icons.loading }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -21,12 +21,12 @@
|
||||||
<div class="dplayer-controller-mask"></div>
|
<div class="dplayer-controller-mask"></div>
|
||||||
<div class="dplayer-controller">
|
<div class="dplayer-controller">
|
||||||
<div class="dplayer-icons dplayer-comment-box">
|
<div class="dplayer-icons dplayer-comment-box">
|
||||||
<button class="dplayer-icon dplayer-comment-setting-icon" data-balloon="{{ tran('Setting') }}" data-balloon-pos="up">
|
<button class="dplayer-icon dplayer-comment-setting-icon" data-balloon="{{ tran('setting') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.pallette }}</span>
|
<span class="dplayer-icon-content">{{@ icons.pallette }}</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dplayer-comment-setting-box">
|
<div class="dplayer-comment-setting-box">
|
||||||
<div class="dplayer-comment-setting-color">
|
<div class="dplayer-comment-setting-color">
|
||||||
<div class="dplayer-comment-setting-title">{{ tran('Set danmaku color') }}</div>
|
<div class="dplayer-comment-setting-title">{{ tran('set-danmaku-color') }}</div>
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#fff" checked>
|
<input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#fff" checked>
|
||||||
<span style="background: #fff;"></span>
|
<span style="background: #fff;"></span>
|
||||||
|
|
@ -53,23 +53,23 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-comment-setting-type">
|
<div class="dplayer-comment-setting-type">
|
||||||
<div class="dplayer-comment-setting-title">{{ tran('Set danmaku type') }}</div>
|
<div class="dplayer-comment-setting-title">{{ tran('set-danmaku-type') }}</div>
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="1">
|
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="1">
|
||||||
<span>{{ tran('Top') }}</span>
|
<span>{{ tran('top') }}</span>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="0" checked>
|
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="0" checked>
|
||||||
<span>{{ tran('Rolling') }}</span>
|
<span>{{ tran('rolling') }}</span>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="2">
|
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="2">
|
||||||
<span>{{ tran('Bottom') }}</span>
|
<span>{{ tran('bottom') }}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input class="dplayer-comment-input" type="text" placeholder="{{ tran('Input danmaku, hit Enter') }}" maxlength="30">
|
<input class="dplayer-comment-input" type="text" placeholder="{{ tran('input-danmaku-enter') }}" maxlength="30">
|
||||||
<button class="dplayer-icon dplayer-send-icon" data-balloon="{{ tran('Send') }}" data-balloon-pos="up">
|
<button class="dplayer-icon dplayer-send-icon" data-balloon="{{ tran('send') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.send }}</span>
|
<span class="dplayer-icon-content">{{@ icons.send }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
<span class="dplayer-dtime">0:00</span>
|
<span class="dplayer-dtime">0:00</span>
|
||||||
</span>
|
</span>
|
||||||
{{ if options.live }}
|
{{ if options.live }}
|
||||||
<span class="dplayer-live-badge"><span class="dplayer-live-dot" style="background: {{ options.theme }};"></span>{{ tran('Live') }}</span>
|
<span class="dplayer-live-badge"><span class="dplayer-live-dot" style="background: {{ options.theme }};"></span>{{ tran('live') }}</span>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-icons dplayer-icons-right">
|
<div class="dplayer-icons dplayer-icons-right">
|
||||||
|
|
@ -111,60 +111,83 @@
|
||||||
</div>
|
</div>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
{{ if options.screenshot }}
|
{{ if options.screenshot }}
|
||||||
<div class="dplayer-icon dplayer-camera-icon" data-balloon="{{ tran('Screenshot') }}" data-balloon-pos="up">
|
<div class="dplayer-icon dplayer-camera-icon" data-balloon="{{ tran('screenshot') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.camera }}</span>
|
<span class="dplayer-icon-content">{{@ icons.camera }}</span>
|
||||||
</div>
|
</div>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
{{ if options.airplay }}
|
{{ if options.airplay }}
|
||||||
<div class="dplayer-icon dplayer-airplay-icon" data-balloon="{{ tran('AirPlay') }}" data-balloon-pos="up">
|
<div class="dplayer-icon dplayer-airplay-icon" data-balloon="{{ tran('airplay') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.airplay }}</span>
|
<span class="dplayer-icon-content">{{@ icons.airplay }}</span>
|
||||||
</div>
|
</div>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
|
{{ if options.chromecast }}
|
||||||
|
<div class="dplayer-icon dplayer-chromecast-icon" data-balloon="{{ tran('chromecast') }}" data-balloon-pos="up">
|
||||||
|
<span class="dplayer-icon-content">{{@ icons.chromecast }}</span>
|
||||||
|
</div>
|
||||||
|
{{ /if }}
|
||||||
<div class="dplayer-comment">
|
<div class="dplayer-comment">
|
||||||
<button class="dplayer-icon dplayer-comment-icon" data-balloon="{{ tran('Send danmaku') }}" data-balloon-pos="up">
|
<button class="dplayer-icon dplayer-comment-icon" data-balloon="{{ tran('send-danmaku') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.comment }}</span>
|
<span class="dplayer-icon-content">{{@ icons.comment }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{{ if options.subtitle }}
|
{{ if options.subtitle }}
|
||||||
|
{{ if (typeof options.subtitle.url === 'string') }}
|
||||||
<div class="dplayer-subtitle-btn">
|
<div class="dplayer-subtitle-btn">
|
||||||
<button class="dplayer-icon dplayer-subtitle-icon" data-balloon="{{ tran('Hide subtitle') }}" data-balloon-pos="up">
|
<button class="dplayer-icon dplayer-subtitle-icon" data-balloon="{{ tran('hide-subs') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.subtitle }}</span>
|
<span class="dplayer-icon-content">{{@ icons.subtitle }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{{ else }}
|
||||||
|
<div class="dplayer-subtitles">
|
||||||
|
<button class="dplayer-icon dplayer-subtitles-icon" data-balloon="{{ tran('subtitle') }}" data-balloon-pos="up">
|
||||||
|
<span class="dplayer-icon-content">{{@ icons.subtitle }}</span>
|
||||||
|
</button>
|
||||||
|
<div class="dplayer-subtitles-box">
|
||||||
|
<div class="dplayer-subtitles-panel">
|
||||||
|
{{ each options.subtitle.url }}
|
||||||
|
<div class="dplayer-subtitles-item" data-subtitle="{{ $value.url }}">
|
||||||
|
<!-- if lang, show tran(lang). if lang and name, show name + (tran(lang)). if name, show name. off option use lang for translation. -->
|
||||||
|
<span class="dplayer-label">{{ $value.lang ? $value.name ? $value.name+' ('+tran($value.lang)+')' : tran($value.lang) : $value.name }}</span>
|
||||||
|
</div>
|
||||||
|
{{ /each }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ /if }}
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
<div class="dplayer-setting">
|
<div class="dplayer-setting">
|
||||||
<button class="dplayer-icon dplayer-setting-icon" data-balloon="{{ tran('Setting') }}" data-balloon-pos="up">
|
<button class="dplayer-icon dplayer-setting-icon" data-balloon="{{ tran('setting') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.setting }}</span>
|
<span class="dplayer-icon-content">{{@ icons.setting }}</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dplayer-setting-box">
|
<div class="dplayer-setting-box">
|
||||||
<div class="dplayer-setting-origin-panel">
|
<div class="dplayer-setting-origin-panel">
|
||||||
<div class="dplayer-setting-item dplayer-setting-speed">
|
<div class="dplayer-setting-item dplayer-setting-speed">
|
||||||
<span class="dplayer-label">{{ tran('Speed') }}</span>
|
<span class="dplayer-label">{{ tran('speed') }}</span>
|
||||||
<div class="dplayer-toggle">{{@ icons.right }}</div>
|
<div class="dplayer-toggle">{{@ icons.right }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-setting-item dplayer-setting-loop">
|
<div class="dplayer-setting-item dplayer-setting-loop">
|
||||||
<span class="dplayer-label">{{ tran('Loop') }}</span>
|
<span class="dplayer-label">{{ tran('loop') }}</span>
|
||||||
<div class="dplayer-toggle">
|
<div class="dplayer-toggle">
|
||||||
<input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle">
|
<input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle">
|
||||||
<label for="dplayer-toggle"></label>
|
<label for="dplayer-toggle"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-setting-item dplayer-setting-showdan">
|
<div class="dplayer-setting-item dplayer-setting-showdan">
|
||||||
<span class="dplayer-label">{{ tran('Show danmaku') }}</span>
|
<span class="dplayer-label">{{ tran('show-danmaku') }}</span>
|
||||||
<div class="dplayer-toggle">
|
<div class="dplayer-toggle">
|
||||||
<input class="dplayer-showdan-setting-input" type="checkbox" name="dplayer-toggle-dan">
|
<input class="dplayer-showdan-setting-input" type="checkbox" name="dplayer-toggle-dan">
|
||||||
<label for="dplayer-toggle-dan"></label>
|
<label for="dplayer-toggle-dan"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-setting-item dplayer-setting-danunlimit">
|
<div class="dplayer-setting-item dplayer-setting-danunlimit">
|
||||||
<span class="dplayer-label">{{ tran('Unlimited danmaku') }}</span>
|
<span class="dplayer-label">{{ tran('unlimited-danmaku') }}</span>
|
||||||
<div class="dplayer-toggle">
|
<div class="dplayer-toggle">
|
||||||
<input class="dplayer-danunlimit-setting-input" type="checkbox" name="dplayer-toggle-danunlimit">
|
<input class="dplayer-danunlimit-setting-input" type="checkbox" name="dplayer-toggle-danunlimit">
|
||||||
<label for="dplayer-toggle-danunlimit"></label>
|
<label for="dplayer-toggle-danunlimit"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-setting-item dplayer-setting-danmaku">
|
<div class="dplayer-setting-item dplayer-setting-danmaku">
|
||||||
<span class="dplayer-label">{{ tran('Opacity for danmaku') }}</span>
|
<span class="dplayer-label">{{ tran('opacity-danmaku') }}</span>
|
||||||
<div class="dplayer-danmaku-bar-wrap">
|
<div class="dplayer-danmaku-bar-wrap">
|
||||||
<div class="dplayer-danmaku-bar">
|
<div class="dplayer-danmaku-bar">
|
||||||
<div class="dplayer-danmaku-bar-inner">
|
<div class="dplayer-danmaku-bar-inner">
|
||||||
|
|
@ -177,17 +200,17 @@
|
||||||
<div class="dplayer-setting-speed-panel">
|
<div class="dplayer-setting-speed-panel">
|
||||||
{{ each options.playbackSpeed }}
|
{{ each options.playbackSpeed }}
|
||||||
<div class="dplayer-setting-speed-item" data-speed="{{ $value }}">
|
<div class="dplayer-setting-speed-item" data-speed="{{ $value }}">
|
||||||
<span class="dplayer-label">{{ $value === 1 ? tran('Normal') : $value }}</span>
|
<span class="dplayer-label">{{ $value === 1 ? tran('normal') : $value }}</span>
|
||||||
</div>
|
</div>
|
||||||
{{ /each }}
|
{{ /each }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-full">
|
<div class="dplayer-full">
|
||||||
<button class="dplayer-icon dplayer-full-in-icon" data-balloon="{{ tran('Web full screen') }}" data-balloon-pos="up">
|
<button class="dplayer-icon dplayer-full-in-icon" data-balloon="{{ tran('web-fullscreen') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.fullWeb }}</span>
|
<span class="dplayer-icon-content">{{@ icons.fullWeb }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="dplayer-icon dplayer-full-icon" data-balloon="{{ tran('Full screen') }}" data-balloon-pos="up">
|
<button class="dplayer-icon dplayer-full-icon" data-balloon="{{ tran('fullscreen') }}" data-balloon-pos="up">
|
||||||
<span class="dplayer-icon-content">{{@ icons.full }}</span>
|
<span class="dplayer-icon-content">{{@ icons.full }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -247,11 +270,11 @@
|
||||||
<div class="dplayer-menu">
|
<div class="dplayer-menu">
|
||||||
{{ each options.contextmenu }}
|
{{ each options.contextmenu }}
|
||||||
<div class="dplayer-menu-item">
|
<div class="dplayer-menu-item">
|
||||||
<a{{ if $value.link }} target="_blank"{{ /if }} href="{{ $value.link || 'javascript:void(0);' }}">{{ tran($value.text) }}</a>
|
<a{{ if $value.link }} target="_blank"{{ /if }} href="{{ $value.link || 'javascript:void(0);' }}">{{ if $value.key }} {{ tran($value.key) }}{{ /if }}{{ if $value.text }} {{$value.text}}{{ /if }}</a>
|
||||||
</div>
|
</div>
|
||||||
{{ /each }}
|
{{ /each }}
|
||||||
</div>
|
</div>
|
||||||
<div class="dplayer-notice"></div>
|
<div class="dplayer-notice-list"></div>
|
||||||
<button class="dplayer-mobile-play">
|
<button class="dplayer-mobile-play">
|
||||||
{{@ icons.play }}
|
{{@ icons.play }}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -7,9 +7,16 @@
|
||||||
{{ if pic }}poster="{{ pic }}"{{ /if }}
|
{{ if pic }}poster="{{ pic }}"{{ /if }}
|
||||||
{{ if screenshot || enableSubtitle }}crossorigin="anonymous"{{ /if }}
|
{{ if screenshot || enableSubtitle }}crossorigin="anonymous"{{ /if }}
|
||||||
{{ if preload }}preload="{{ preload }}"{{ /if }}
|
{{ if preload }}preload="{{ preload }}"{{ /if }}
|
||||||
{{ if url }}src="{{ url }}"{{ /if }}
|
{{ if airplay }}
|
||||||
|
nosrc
|
||||||
|
{{ else if url }}
|
||||||
|
src="{{ url }}"
|
||||||
|
{{ /if }}
|
||||||
>
|
>
|
||||||
|
{{ if airplay }}
|
||||||
|
<source src="{{ url }}">
|
||||||
|
{{ /if}}
|
||||||
{{ if enableSubtitle }}
|
{{ if enableSubtitle }}
|
||||||
<track kind="metadata" default src="{{ subtitle.url }}"></track>
|
<track class="dplayer-subtrack" kind="metadata" default src="{{ typeof subtitle.url === 'string' ? subtitle.url : subtitle.url[subtitle.index].url }}"></track>
|
||||||
{{ /if }}
|
{{ /if }}
|
||||||
</video>
|
</video>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# https://tea.xyz/what-is-this-file
|
||||||
|
---
|
||||||
|
version: 1.0.0
|
||||||
|
codeOwners:
|
||||||
|
- '0x185bfcef7b37010e2511309048a130f477f54fBf'
|
||||||
|
quorum: 1
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const GitRevisionPlugin = require('git-revision-webpack-plugin');
|
const { GitRevisionPlugin } = require('git-revision-webpack-plugin');
|
||||||
const gitRevisionPlugin = new GitRevisionPlugin();
|
const gitRevisionPlugin = new GitRevisionPlugin();
|
||||||
const autoprefixer = require('autoprefixer');
|
|
||||||
const cssnano = require('cssnano');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
|
|
@ -26,7 +24,13 @@ module.exports = {
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: ['node_modules'],
|
modules: ['node_modules'],
|
||||||
extensions: ['.js', '.scss'],
|
extensions: ['.js', '.less'],
|
||||||
|
fallback: {
|
||||||
|
dgram: false,
|
||||||
|
fs: false,
|
||||||
|
net: false,
|
||||||
|
tls: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
|
|
@ -45,7 +49,7 @@ module.exports = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.less$/,
|
||||||
use: [
|
use: [
|
||||||
'style-loader',
|
'style-loader',
|
||||||
{
|
{
|
||||||
|
|
@ -57,10 +61,12 @@ module.exports = {
|
||||||
{
|
{
|
||||||
loader: 'postcss-loader',
|
loader: 'postcss-loader',
|
||||||
options: {
|
options: {
|
||||||
plugins: [autoprefixer, cssnano],
|
postcssOptions: {
|
||||||
|
plugins: ['postcss-preset-env'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'sass-loader',
|
'less-loader',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -82,17 +88,11 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
devServer: {
|
devServer: {
|
||||||
|
static: {
|
||||||
|
directory: path.join(__dirname, '..', 'demo'),
|
||||||
|
},
|
||||||
compress: true,
|
compress: true,
|
||||||
contentBase: path.resolve(__dirname, '..', 'demo'),
|
|
||||||
clientLogLevel: 'none',
|
|
||||||
quiet: false,
|
|
||||||
open: true,
|
open: true,
|
||||||
historyApiFallback: {
|
|
||||||
disableDotRule: true,
|
|
||||||
},
|
|
||||||
watchOptions: {
|
|
||||||
ignored: /node_modules/,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|
@ -102,13 +102,6 @@ module.exports = {
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
||||||
node: {
|
|
||||||
dgram: 'empty',
|
|
||||||
fs: 'empty',
|
|
||||||
net: 'empty',
|
|
||||||
tls: 'empty',
|
|
||||||
},
|
|
||||||
|
|
||||||
performance: {
|
performance: {
|
||||||
hints: false,
|
hints: false,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const GitRevisionPlugin = require('git-revision-webpack-plugin');
|
const { GitRevisionPlugin } = require('git-revision-webpack-plugin');
|
||||||
const gitRevisionPlugin = new GitRevisionPlugin();
|
const gitRevisionPlugin = new GitRevisionPlugin();
|
||||||
const autoprefixer = require('autoprefixer');
|
|
||||||
const cssnano = require('cssnano');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
|
|
@ -28,7 +26,13 @@ module.exports = {
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: ['node_modules'],
|
modules: ['node_modules'],
|
||||||
extensions: ['.js', '.scss'],
|
extensions: ['.js', '.less'],
|
||||||
|
fallback: {
|
||||||
|
dgram: false,
|
||||||
|
fs: false,
|
||||||
|
net: false,
|
||||||
|
tls: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
|
|
@ -48,7 +52,7 @@ module.exports = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.less$/,
|
||||||
use: [
|
use: [
|
||||||
'style-loader',
|
'style-loader',
|
||||||
{
|
{
|
||||||
|
|
@ -60,10 +64,12 @@ module.exports = {
|
||||||
{
|
{
|
||||||
loader: 'postcss-loader',
|
loader: 'postcss-loader',
|
||||||
options: {
|
options: {
|
||||||
plugins: [autoprefixer, cssnano],
|
postcssOptions: {
|
||||||
|
plugins: ['postcss-preset-env'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'sass-loader',
|
'less-loader',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -90,11 +96,4 @@ module.exports = {
|
||||||
GIT_HASH: JSON.stringify(gitRevisionPlugin.version()),
|
GIT_HASH: JSON.stringify(gitRevisionPlugin.version()),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
||||||
node: {
|
|
||||||
dgram: 'empty',
|
|
||||||
fs: 'empty',
|
|
||||||
net: 'empty',
|
|
||||||
tls: 'empty',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue