Compare commits
No commits in common. "master" and "v1.26.0" have entirely different histories.
|
|
@ -0,0 +1,2 @@
|
|||
dist
|
||||
demo
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
pnpm exec lint-staged
|
||||
64
README.md
64
README.md
|
|
@ -8,11 +8,13 @@
|
|||
[](https://www.npmjs.com/package/dplayer)
|
||||
[](https://github.com/MoePlayer/DPlayer/blob/master/LICENSE)
|
||||
[](https://www.npmjs.com/package/dplayer)
|
||||
[](https://www.jsdelivr.com/package/npm/dplayer)
|
||||
[](https://github.com/MoePlayer/DPlayer/tree/master/dist)
|
||||
[](https://travis-ci.org/MoePlayer/DPlayer)
|
||||
[](https://david-dm.org/MoePlayer/DPlayer#info=devDependencies)
|
||||
|
||||
## Introduction
|
||||
|
||||

|
||||

|
||||
|
||||
DPlayer is a lovely HTML5 danmaku video player to help people build video and danmaku easily.
|
||||
|
||||
|
|
@ -38,24 +40,40 @@ 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)
|
||||
|
||||
**[Docs](https://dplayer.diygod.dev/)**
|
||||
**[Docs](http://dplayer.js.org)**
|
||||
|
||||
**[中文文档](https://dplayer.diygod.dev/zh/)**
|
||||
**[中文文档](http://dplayer.js.org/#/zh-Hans/)**
|
||||
|
||||
## Thanks
|
||||
|
||||
### 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">
|
||||
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Sponsors
|
||||
|
||||
| [极酷社](https://www.acg.app) |
|
||||
| :---------------------------: |
|
||||
|
||||
|
||||
### Contributors
|
||||
|
||||
<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
|
||||
|
||||
Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
||||
|
|
@ -82,13 +100,11 @@ Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlay
|
|||
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
||||
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
||||
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
||||
- [rc-dplayer](https://github.com/tianfeng98/rc-dplayer): React
|
||||
|
||||
### Other
|
||||
|
||||
- [DPlayer-Lite](https://github.com/kn007/DPlayer-Lite): lite version
|
||||
- [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.
|
||||
- [hlsjs-p2p-engine](https://github.com/cdnbye/hlsjs-p2p-engine)
|
||||
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlayer/issues/31)
|
||||
|
||||
## Who use DPlayer?
|
||||
|
|
@ -103,34 +119,26 @@ Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/DPlay
|
|||
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
||||
- [Cloudreve](https://github.com/HFO4/Cloudreve): 基于 ThinkPHP 构建的网盘系统
|
||||
- [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)
|
||||
|
||||
## Donate
|
||||
|
||||
DPlayer is an MIT licensed open source project and completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing.
|
||||
|
||||
You can support DPlayer via donations.
|
||||
## One-time Donations
|
||||
|
||||
### Recurring Donation
|
||||
We accept donations through these channels:
|
||||
|
||||
- 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)
|
||||
- [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
|
||||
|
||||
|
|
|
|||
28
demo/demo.js
28
demo/demo.js
|
|
@ -65,23 +65,7 @@ function initPlayers() {
|
|||
thumbnails: 'https://i.loli.net/2019/06/06/5cf8c5d9cec8510758.jpg'
|
||||
},
|
||||
subtitle: {
|
||||
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'
|
||||
url: 'https://s-sh-17-dplayercdn.oss.dogecdn.com/hikarunara.vtt'
|
||||
},
|
||||
danmaku: {
|
||||
id: '9E2E3368B56CDBB4',
|
||||
|
|
@ -99,12 +83,10 @@ function initPlayers() {
|
|||
loop: true,
|
||||
screenshot: true,
|
||||
airplay: true,
|
||||
chromecast: true,
|
||||
hotkey: true,
|
||||
logo: 'https://i.loli.net/2019/06/06/5cf8c5d94521136430.png',
|
||||
volume: 0.2,
|
||||
mutex: true,
|
||||
lang: 'zh-cn',
|
||||
video: {
|
||||
url: 'https://api.dogecloud.com/player/get.mp4?vcode=5ac682e6f8231991&userId=17&ext=.mp4',
|
||||
pic: 'https://i.loli.net/2019/06/06/5cf8c5d9c57b510947.png',
|
||||
|
|
@ -121,13 +103,11 @@ function initPlayers() {
|
|||
danmaku: {
|
||||
id: '9E2E3368B56CDBB4',
|
||||
api: 'https://api.prprpr.me/dplayer/',
|
||||
addition: ['https://s-sh-17-dplayercdn.oss.dogecdn.com/1678963.json'],
|
||||
token: 'tokendemo',
|
||||
maximum: 3000,
|
||||
user: 'DIYgod',
|
||||
bottom: '15%',
|
||||
unlimited: true,
|
||||
speedRate: 0.5,
|
||||
unlimited: true
|
||||
},
|
||||
contextmenu: [
|
||||
{
|
||||
|
|
@ -157,7 +137,7 @@ function initPlayers() {
|
|||
const eventsEle = document.getElementById('events');
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
dp2.on(events[i], (info) => {
|
||||
eventsEle.innerHTML += `<p>Event: ${events[i]} ${info?`Data: <span>${JSON.stringify(info)}</span>`:''}</p>`;
|
||||
eventsEle.innerHTML += '<p>Event: ' + events[i] + '</p>';
|
||||
eventsEle.scrollTop = eventsEle.scrollHeight;
|
||||
});
|
||||
}
|
||||
|
|
@ -264,7 +244,7 @@ function clearPlayers() {
|
|||
}
|
||||
|
||||
function switchDPlayer() {
|
||||
if (dp2.options.danmaku.id !== '5rGf5Y2X55qu6Z2p') {
|
||||
if (dp2.option.danmaku.id !== '5rGf5Y2X55qu6Z2p') {
|
||||
dp2.switchVideo({
|
||||
url: 'http://static.smartisanos.cn/common/video/t1-ui.mp4',
|
||||
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,16 +71,12 @@ export default {
|
|||
methods: {
|
||||
load: function () {
|
||||
this.options.container = this.$refs.dplayer;
|
||||
setTimeout(() => {
|
||||
this.dplayer = new window.DPlayer(this.options);
|
||||
}, 0);
|
||||
this.dplayer = new window.DPlayer(this.options);
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
if (this.immediate) {
|
||||
setTimeout(() => {
|
||||
this.dplayer = new window.DPlayer(this.options);
|
||||
}, 0);
|
||||
this.dplayer = new window.DPlayer(this.options);
|
||||
}
|
||||
},
|
||||
beforeDestroy: function () {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,22 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
'@vuepress/back-to-top': true,
|
||||
umami: {
|
||||
trackerUrl: 'https://umami.diygod.dev',
|
||||
siteId: 'f3b469a2-8054-4bbb-8873-4035761aa4e3',
|
||||
'@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,
|
||||
},
|
||||
locales: {
|
||||
'/zh/': {
|
||||
|
|
@ -26,11 +38,10 @@ module.exports = {
|
|||
['script', { src: 'https://cdn.jsdelivr.net/webtorrent/latest/webtorrent.min.js' }],
|
||||
['script', { src: 'https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js' }],
|
||||
],
|
||||
theme: 'vuepress-theme-dplayer',
|
||||
themeConfig: {
|
||||
repo: 'MoePlayer/DPlayer',
|
||||
editLinks: true,
|
||||
docsDir: '.',
|
||||
docsDir: 'docs',
|
||||
locales: {
|
||||
'/zh/': {
|
||||
lang: 'zh-CN',
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
dplayer.js.org
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = {
|
||||
extend: '@vuepress/theme-default',
|
||||
};
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"name": "vuepress-theme-dplayer",
|
||||
"main": "index.js"
|
||||
}
|
||||
|
|
@ -8,6 +8,10 @@ Let's make DPlayer better, feel free to submit yours in [`Let me know!`](https:/
|
|||
|
||||
## Help
|
||||
|
||||
### Joining the Discussion
|
||||
|
||||
- [Telegram Group](https://t.me/adplayer)
|
||||
|
||||
### Creating issue
|
||||
|
||||
- [MoePlayer/DPlayer/issues](https://github.com/MoePlayer/DPlayer/issues)
|
||||
|
|
@ -36,7 +40,6 @@ Let's make DPlayer better, feel free to submit yours in [`Let me know!`](https:/
|
|||
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
||||
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
||||
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
||||
- [rc-dplayer](https://github.com/tianfeng98/rc-dplayer): React
|
||||
|
||||
### Other
|
||||
|
||||
|
|
@ -54,13 +57,6 @@ Let's make DPlayer better, feel free to submit yours in [`Let me know!`](https:/
|
|||
- [纸飞机南航青年网络社区](http://my.nuaa.edu.cn/video-video.html): 南京航空航天大学门户网站
|
||||
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
||||
- [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
|
||||
|
||||
|
|
|
|||
101
docs/guide.md
101
docs/guide.md
|
|
@ -14,16 +14,28 @@ sidebar: auto
|
|||
|
||||
## Special Thanks
|
||||
|
||||
### Sponsors
|
||||
### Special Sponsors
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
||||
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||
<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">
|
||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Sponsors
|
||||
|
||||
| [极酷社](https://www.acg.app) |
|
||||
| :---------------------------: |
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Using npm:
|
||||
|
|
@ -91,15 +103,13 @@ You can custom your player instance by those options
|
|||
| loop | false | video loop |
|
||||
| lang | navigator.language.toLowerCase() | values: 'en', 'zh-cn', 'zh-tw' |
|
||||
| screenshot | false | enable screenshot, if true, video and video poster must enable Cross-Origin |
|
||||
| airplay | false | enable airplay in Safari |
|
||||
| chromecast | false | enable Chromecast |
|
||||
| airplay | true | enable airplay in Safari |
|
||||
| hotkey | true | enable hotkey, support FF, FR, volume control, play & pause |
|
||||
| preload | 'auto' | values: 'none', 'metadata', 'auto' |
|
||||
| volume | 0.7 | default volume, notice that player will remember user setting, default volume will not work after user set volume themselves |
|
||||
| playbackSpeed | [0.5, 0.75, 1, 1.25, 1.5, 2] | optional playback speed, or or you can set a custom one |
|
||||
| logo | - | showing logo in the top left corner, you can adjust its size and position by CSS |
|
||||
| apiBackend | - | getting and sending danmaku in your way, see [#live](#live) |
|
||||
| preventClickToggle | false | prevent toggle video play/pause status when click player |
|
||||
| video | - | video info |
|
||||
| video.quality | - | see [#Quality switching](#quality-switching) |
|
||||
| video.defaultQuality | - | see [#Quality switching](#quality-switching) |
|
||||
|
|
@ -123,7 +133,6 @@ You can custom your player instance by those options
|
|||
| danmaku.user | 'DIYgod' | danmaku user name |
|
||||
| danmaku.bottom | - | values like: '10px' '10%', the distance between the danmaku bottom and player bottom, in order to prevent warding off subtitle |
|
||||
| danmaku.unlimited | false | display all danmaku even though danmaku overlap, notice that player will remember user setting, default setting will not work after user set it themselves |
|
||||
| danmaku.speedRate | 1 | danmaku speed multiplier, the larger the faster |
|
||||
| contextmenu | [] | custom contextmenu |
|
||||
| highlight | [] | custom time markers upon progress bar |
|
||||
| mutex | true | prevent to play multiple player at the same time, pause other players when this player start play |
|
||||
|
|
@ -163,7 +172,6 @@ const dp = new DPlayer({
|
|||
user: 'DIYgod',
|
||||
bottom: '15%',
|
||||
unlimited: true,
|
||||
speedRate: 0.5,
|
||||
},
|
||||
contextmenu: [
|
||||
{
|
||||
|
|
@ -204,7 +212,7 @@ const dp = new DPlayer({
|
|||
|
||||
- `dp.toggle()`: toggle between play and pause
|
||||
|
||||
- `dp.on(event: string, handler: function)`: bind video and player events, [see more details](https://dplayer.diygod.dev/guide.html#event-binding)
|
||||
- `dp.on(event: string, handler: function)`: bind video and player events, [see more details](http://dplayer.js.org/#/home?id=event-binding)
|
||||
|
||||
- `dp.switchVideo(video, danmaku)`: switch to a new video
|
||||
|
||||
|
|
@ -412,56 +420,15 @@ 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 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)
|
||||
|
||||
|
|
@ -736,32 +703,22 @@ DPlayer can work with any MSE library via `customType` option.
|
|||
|
||||
```html
|
||||
<div id="dplayer"></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/cdnbye@latest"></script>
|
||||
<script src="pearplayer.js"></script>
|
||||
<script src="DPlayer.min.js"></script>
|
||||
```
|
||||
|
||||
```js
|
||||
var type = 'normal';
|
||||
if (Hls.isSupported() && Hls.WEBRTC_SUPPORT) {
|
||||
type = 'customHls';
|
||||
}
|
||||
const dp = new DPlayer({
|
||||
container: document.getElementById('dplayer'),
|
||||
video: {
|
||||
url: 'demo.m3u8',
|
||||
type: type,
|
||||
url: 'https://qq.webrtc.win/tv/Pear-Demo-Yosemite_National_Park.mp4',
|
||||
type: 'pearplayer',
|
||||
customType: {
|
||||
customHls: function (video, player) {
|
||||
const hls = new Hls({
|
||||
debug: false,
|
||||
// Other hlsjsConfig options provided by hls.js
|
||||
p2pConfig: {
|
||||
live: false,
|
||||
// Other p2pConfig options provided by CDNBye http://www.cdnbye.com/en/
|
||||
},
|
||||
pearplayer: function (video, player) {
|
||||
new PearPlayer(video, {
|
||||
src: video.src,
|
||||
autoplay: player.options.autoplay,
|
||||
});
|
||||
hls.loadSource(video.src);
|
||||
hls.attachMedia(video);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -790,11 +747,11 @@ const dp = new DPlayer({
|
|||
apiBackend: {
|
||||
read: function (options) {
|
||||
console.log('Pretend to connect WebSocket');
|
||||
options.success([]);
|
||||
callback();
|
||||
},
|
||||
send: function (options) {
|
||||
console.log('Pretend to send danmaku via WebSocket', options.data);
|
||||
options.success();
|
||||
callback();
|
||||
},
|
||||
},
|
||||
video: {
|
||||
|
|
@ -829,4 +786,4 @@ For full browser support it should look like this:
|
|||
|
||||
### Why can't player autoplay in some mobile browsers?
|
||||
|
||||
Most mobile browsers forbid video autoplay, you wont be able to achieve it without hacks.
|
||||
Most mobile browsers forbid video autoplay, you wont be able to achieve it without hacks.
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
9329
docs/pnpm-lock.yaml
9329
docs/pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -10,30 +10,44 @@ 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 :)
|
||||
|
||||
You can support DPlayer via donations.
|
||||
You can support DPlayer development via the following methods:
|
||||
|
||||
### Recurring Donation
|
||||
## One-time Donations
|
||||
|
||||
Recurring donors will be rewarded via express issue response, or even have your name displayed on our GitHub page and website.
|
||||
We accept donations through these channels:
|
||||
|
||||
- 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)
|
||||
- [WeChat Pay](https://i.imgur.com/aq6PtWa.png)
|
||||
- [Alipay](https://i.imgur.com/wv1Pj2k.png)
|
||||
|
||||
## Sponsors
|
||||
## Recurring Pledges
|
||||
|
||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
||||
<img width="222px" src="hhttps://player.dogecloud.com/img/logo_with_product3.png">
|
||||
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">
|
||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Sponsors
|
||||
|
||||
| [极酷社](https://www.acg.app) |
|
||||
| :---------------------------: |
|
||||
|
||||
|
||||
## DPlayer contributors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
home: true
|
||||
actionText: Get Started →
|
||||
actionLink: /zh/guide/
|
||||
actionLink: /guide/
|
||||
footer: MIT Licensed | Made with love by DIYgod
|
||||
---
|
||||
|
||||
|
|
@ -9,4 +9,4 @@ footer: MIT Licensed | Made with love by DIYgod
|
|||
<DPlayer :immediate="true"></DPlayer>
|
||||
</div>
|
||||
|
||||
<div class="hero custom"><p class="action"><router-link to="/zh/guide/" class="nav-link action-button">快速上手 →</router-link></p></div>
|
||||
<div class="hero custom"><p class="action"><router-link to="/guide/" class="nav-link action-button">快速上手 →</router-link></p></div>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ sidebar: auto
|
|||
|
||||
## 帮助
|
||||
|
||||
### 参与讨论
|
||||
|
||||
- [Telegram 群](https://t.me/adplayer)
|
||||
|
||||
### 提交 issue
|
||||
|
||||
- [MoePlayer/DPlayer/issues](https://github.com/MoePlayer/DPlayer/issues)
|
||||
|
|
@ -36,7 +40,6 @@ sidebar: auto
|
|||
- [Selection](https://github.com/GreatSatan79/Selection): WordPress
|
||||
- [Vue-DPlayer](https://github.com/sinchang/vue-dplayer): Vue
|
||||
- [react-dplayer](https://github.com/hnsylitao/react-dplayer): React
|
||||
- [rc-dplayer](https://github.com/tianfeng98/rc-dplayer): React
|
||||
|
||||
### 其他
|
||||
|
||||
|
|
@ -54,10 +57,3 @@ sidebar: auto
|
|||
- [纸飞机南航青年网络社区](http://my.nuaa.edu.cn/video-video.html): 南京航空航天大学门户网站
|
||||
- [otomads](https://otomads.com/): 专注于音 MAD 的视频弹幕网站
|
||||
- [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)
|
||||
|
|
|
|||
105
docs/zh/guide.md
105
docs/zh/guide.md
|
|
@ -14,14 +14,26 @@ sidebar: auto
|
|||
|
||||
## Special Thanks
|
||||
|
||||
### 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">
|
||||
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Sponsors
|
||||
|
||||
| [极酷社](https://www.acg.app) |
|
||||
| :---------------------------: |
|
||||
|
||||
|
||||
## 安装
|
||||
|
||||
使用 npm:
|
||||
|
|
@ -82,14 +94,12 @@ DPlayer 有丰富的参数可以自定义你的播放器实例
|
|||
| lang | navigator.language.toLowerCase() | 可选值: 'en', 'zh-cn', 'zh-tw' |
|
||||
| screenshot | false | 开启截图,如果开启,视频和视频封面需要允许跨域 |
|
||||
| hotkey | true | 开启热键,支持快进、快退、音量控制、播放暂停 |
|
||||
| airplay | false | 在 Safari 中开启 AirPlay |
|
||||
| chromecast | false | 启用 Chromecast |
|
||||
| airplay | true | 在 Safari 中开启 AirPlay |
|
||||
| preload | 'auto' | 视频预加载,可选值: 'none', 'metadata', 'auto' |
|
||||
| volume | 0.7 | 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 |
|
||||
| playbackSpeed | [0.5, 0.75, 1, 1.25, 1.5, 2] | 可选的播放速率,可以设置成自定义的数组 |
|
||||
| logo | - | 在左上角展示一个 logo,你可以通过 CSS 调整它的大小和位置 |
|
||||
| apiBackend | - | 自定义获取和发送弹幕行为,见[#直播](#直播) |
|
||||
| preventClickToggle | false | 阻止点击播放器时候自动切换播放/暂停 |
|
||||
| video | - | 视频信息 |
|
||||
| video.quality | - | 见[#清晰度切换](#清晰度切换) |
|
||||
| video.defaultQuality | - | 见[#清晰度切换](#清晰度切换) |
|
||||
|
|
@ -113,7 +123,6 @@ DPlayer 有丰富的参数可以自定义你的播放器实例
|
|||
| danmaku.user | 'DIYgod' | 弹幕用户名 |
|
||||
| danmaku.bottom | - | 弹幕距离播放器底部的距离,防止遮挡字幕,取值形如: '10px' '10%' |
|
||||
| danmaku.unlimited | false | 海量弹幕模式,即使重叠也展示全部弹幕,请注意播放器会记忆用户设置,用户手动设置后即失效 |
|
||||
| danmaku.speedRate | 1 | 弹幕速度倍率,越大速度越快 |
|
||||
| contextmenu | [] | 自定义右键菜单 |
|
||||
| highlight | [] | 自定义进度条提示点 |
|
||||
| mutex | true | 互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 |
|
||||
|
|
@ -153,7 +162,6 @@ const dp = new DPlayer({
|
|||
user: 'DIYgod',
|
||||
bottom: '15%',
|
||||
unlimited: true,
|
||||
speedRate: 0.5,
|
||||
},
|
||||
contextmenu: [
|
||||
{
|
||||
|
|
@ -396,56 +404,15 @@ 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`
|
||||
|
||||
<!-- **现成的接口**
|
||||
**现成的接口**
|
||||
|
||||
链接: https://api.prprpr.me/dplayer/ -->
|
||||
链接: https://api.prprpr.me/dplayer/
|
||||
|
||||
每日备份: [DPlayer-data](https://github.com/DIYgod/DPlayer-data)
|
||||
|
||||
|
|
@ -716,36 +683,26 @@ const dp = new DPlayer({
|
|||
|
||||
### 配合其他 MSE 库使用
|
||||
|
||||
DPlayer 可以通过 `customType` 参数与任何 MSE 库一起使用,例如支持 P2P 插件:
|
||||
DPlayer 可以通过 `customType` 参数与任何 MSE 库一起使用
|
||||
|
||||
```html
|
||||
<div id="dplayer"></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/cdnbye@latest"></script>
|
||||
<script src="pearplayer.js"></script>
|
||||
<script src="DPlayer.min.js"></script>
|
||||
```
|
||||
|
||||
```js
|
||||
var type = 'normal';
|
||||
if (Hls.isSupported() && Hls.WEBRTC_SUPPORT) {
|
||||
type = 'customHls';
|
||||
}
|
||||
const dp = new DPlayer({
|
||||
container: document.getElementById('dplayer'),
|
||||
video: {
|
||||
url: 'demo.m3u8',
|
||||
type: type,
|
||||
url: 'https://qq.webrtc.win/tv/Pear-Demo-Yosemite_National_Park.mp4',
|
||||
type: 'pearplayer',
|
||||
customType: {
|
||||
customHls: function (video, player) {
|
||||
const hls = new Hls({
|
||||
debug: false,
|
||||
// Other hlsjsConfig options provided by hls.js
|
||||
p2pConfig: {
|
||||
live: false, // 如果是直播设为true
|
||||
// Other p2pConfig options provided by CDNBye http://www.cdnbye.com/cn/
|
||||
},
|
||||
pearplayer: function (video, player) {
|
||||
new PearPlayer(video, {
|
||||
src: video.src,
|
||||
autoplay: player.options.autoplay,
|
||||
});
|
||||
hls.loadSource(video.src);
|
||||
hls.attachMedia(video);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -772,13 +729,13 @@ const dp = new DPlayer({
|
|||
live: true,
|
||||
danmaku: true,
|
||||
apiBackend: {
|
||||
read: function (options) {
|
||||
read: function (endpoint, callback) {
|
||||
console.log('Pretend to connect WebSocket');
|
||||
options.success([]);
|
||||
callback();
|
||||
},
|
||||
send: function (options) {
|
||||
console.log('Pretend to send danmaku via WebSocket', options.data);
|
||||
options.success();
|
||||
send: function (endpoint, danmakuData, callback) {
|
||||
console.log('Pretend to send danmaku via WebSocket', danmakuData);
|
||||
callback();
|
||||
},
|
||||
},
|
||||
video: {
|
||||
|
|
@ -813,4 +770,4 @@ dp.danmaku.draw(danmaku);
|
|||
|
||||
### 为什么播放器不能在手机上自动播放?
|
||||
|
||||
大多数移动端浏览器禁止了视频自动播放。
|
||||
大多数移动端浏览器禁止了视频自动播放。
|
||||
|
|
|
|||
|
|
@ -10,31 +10,45 @@ DPlayer 是采用 MIT 许可的开源项目,使用完全免费。 但是随着
|
|||
|
||||
如果你是个人开发者并且享受 DPlayer 带来的高开发效率,可以用捐助来表示你的谢意 —— 比如偶尔给我买杯咖啡 :)
|
||||
|
||||
你可以通过下列的方法来赞助 DPlayer 的开发.
|
||||
|
||||
## 周期性赞助
|
||||
|
||||
- 通过 [GitHub](https://github.com/sponsors/DIYgod) 赞助
|
||||
- 通过 [Patreon](https://www.patreon.com/DIYgod) 赞助
|
||||
- 通过 [爱发电](https://afdian.net/@diygod) 赞助
|
||||
- 给我们发邮件联系赞助事宜: <i@diygod.me>
|
||||
你可以通过下列的方法来赞助 DPlayer 的开发。
|
||||
|
||||
## 一次性赞助
|
||||
|
||||
我们通过以下方式接受赞助:
|
||||
我们通过以下方式接受赞助:
|
||||
|
||||
- [微信支付](https://diygod.me/images/wx.jpg)
|
||||
- [支付宝](https://diygod.me/images/zfb.jpg)
|
||||
- [微信支付](https://i.imgur.com/aq6PtWa.png)
|
||||
- [支付宝](https://i.imgur.com/wv1Pj2k.png)
|
||||
- [Paypal](https://www.paypal.me/DIYgod)
|
||||
|
||||
## 赞助商
|
||||
## 周期性赞助
|
||||
|
||||
周期性赞助可以获得额外的回报,比如你的名字或你的公司 logo 会出现在 DPlayer 的 GitHub 仓库和现在我们的官网中。
|
||||
|
||||
- 通过 [Patreon](https://www.patreon.com/DIYgod) 赞助
|
||||
- 给我们发邮件联系赞助事宜: i#diygod.me
|
||||
|
||||
## 当前的顶级赞助商
|
||||
|
||||
### 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">
|
||||
<img height="60px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
||||
<img height="60px" src="https://i.imgur.com/C2NgugY.png">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Sponsors
|
||||
|
||||
| [极酷社](https://www.acg.app) |
|
||||
| :---------------------------: |
|
||||
|
||||
|
||||
## DPlayer 贡献者
|
||||
|
||||
感谢所有贡献者。
|
||||
|
|
|
|||
74
package.json
74
package.json
|
|
@ -1,20 +1,18 @@
|
|||
{
|
||||
"name": "dplayer",
|
||||
"version": "1.27.1",
|
||||
"version": "1.26.0",
|
||||
"description": "Wow, such a lovely HTML5 danmaku video player",
|
||||
"main": "dist/DPlayer.min.js",
|
||||
"scripts": {
|
||||
"start": "npm run dev",
|
||||
"build": "cross-env NODE_ENV=production webpack --config webpack/prod.config.js --progress",
|
||||
"dev": "cross-env NODE_ENV=development webpack serve --config webpack/dev.config.js",
|
||||
"test": "",
|
||||
"format": "prettier \"**/*.{js,json,md}\" --write",
|
||||
"build": "cross-env NODE_ENV=production webpack --config webpack/prod.config.js --progress --display-error-details --colors",
|
||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack/dev.config.js --watch --colors",
|
||||
"test": "eslint src webpack",
|
||||
"format": "eslint \"**/*.js\" --fix && 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:build": "vuepress build docs",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*": "prettier --write --ignore-unknown"
|
||||
"docs:build": "vuepress build docs"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
|
@ -29,6 +27,9 @@
|
|||
"video",
|
||||
"html5"
|
||||
],
|
||||
"gitHooks": {
|
||||
"pre-commit": "npm run format:staged"
|
||||
},
|
||||
"author": "DIYgod",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
|
|
@ -36,43 +37,46 @@
|
|||
},
|
||||
"homepage": "https://github.com/DIYgod/DPlayer#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
"@babel/preset-env": "^7.22.10",
|
||||
"@vuepress/plugin-pwa": "1.9.9",
|
||||
"@babel/core": "^7.6.0",
|
||||
"@babel/preset-env": "^7.4.5",
|
||||
"@vuepress/plugin-back-to-top": "1.5.1",
|
||||
"@vuepress/plugin-google-analytics": "1.5.1",
|
||||
"@vuepress/plugin-pwa": "1.5.1",
|
||||
"art-template": "4.13.2",
|
||||
"art-template-loader": "1.4.3",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"babel-loader": "^9.1.3",
|
||||
"autoprefixer": "^9.6.1",
|
||||
"babel-loader": "^8.0.6",
|
||||
"cross-env": "^7.0.0",
|
||||
"css-loader": "^6.8.1",
|
||||
"cssnano": "^6.0.1",
|
||||
"exports-loader": "^4.0.0",
|
||||
"css-loader": "^3.2.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"eslint": "^7.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",
|
||||
"git-revision-webpack-plugin": "^5.0.0",
|
||||
"husky": "^8.0.3",
|
||||
"less": "^4.2.0",
|
||||
"less-loader": "^11.1.3",
|
||||
"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",
|
||||
"git-revision-webpack-plugin": "^3.0.3",
|
||||
"mini-css-extract-plugin": "0.9.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"prettier": "^2.0.4",
|
||||
"prettier-check": "^2.0.0",
|
||||
"pretty-quick": "^3.0.0",
|
||||
"pretty-quick": "^2.0.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"strip-loader": "^0.1.2",
|
||||
"style-loader": "^3.3.3",
|
||||
"style-loader": "^1.0.0",
|
||||
"svg-inline-loader": "0.8.2",
|
||||
"template-string-optimize-loader": "^3.0.0",
|
||||
"url-loader": "^4.1.0",
|
||||
"webpack": "^5.88.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "^4.15.1",
|
||||
"vuepress": "1.5.1",
|
||||
"webpack": "^4.40.2",
|
||||
"webpack-cli": "3.3.11",
|
||||
"webpack-dev-server": "^3.8.1",
|
||||
"yorkie": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "1.4.0",
|
||||
"axios": "0.19.2",
|
||||
"balloon-css": "^1.0.3",
|
||||
"promise-polyfill": "8.3.0"
|
||||
"promise-polyfill": "8.1.3"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
7396
pnpm-lock.yaml
7396
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -1 +0,0 @@
|
|||
<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>
|
||||
|
Before Width: | Height: | Size: 642 B |
|
|
@ -60,11 +60,11 @@
|
|||
animation: diplayer-loading-dot-fade .8s ease infinite;
|
||||
opacity: 0;
|
||||
transform-origin: 4px 4px;
|
||||
each(range(7), {
|
||||
&.diplayer-loading-dot-@{value} {
|
||||
animation-delay: (@value * 0.1s);
|
||||
@for $i from 7 through 1 {
|
||||
&.diplayer-loading-dot-#{$i} {
|
||||
animation-delay: .1s * $i;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@keyframes diplayer-loading-dot-fade {
|
||||
0% {
|
||||
|
|
@ -408,41 +408,6 @@
|
|||
display: inline-block;
|
||||
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 {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
user-select: none;
|
||||
cursor: default;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0.5px 0.5px 0.5px rgba(0, 0, 0, 0.5);
|
||||
text-shadow: .5px .5px .5px rgba(0, 0, 0, .5);
|
||||
&--demo {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
|
|
@ -24,8 +24,7 @@
|
|||
transform: translateX(100%);
|
||||
&.dplayer-danmaku-move {
|
||||
will-change: transform;
|
||||
animation-name: danmaku;
|
||||
animation-timing-function: linear;
|
||||
animation: danmaku 5s linear;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
}
|
||||
|
|
@ -42,8 +41,7 @@
|
|||
visibility: hidden;
|
||||
&.dplayer-danmaku-move {
|
||||
will-change: visibility;
|
||||
animation-name: danmaku-center;
|
||||
animation-timing-function: linear;
|
||||
animation: danmaku-center 4s linear;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
}
|
||||
|
|
@ -55,4 +53,4 @@
|
|||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
.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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
.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;
|
||||
}
|
||||
|
|
@ -29,7 +29,23 @@
|
|||
margin: 0;
|
||||
padding: 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 {
|
||||
|
|
@ -151,7 +167,6 @@
|
|||
.dplayer-volume,
|
||||
.dplayer-camera-icon,
|
||||
.dplayer-airplay-icon,
|
||||
.dplayer-chromecast-icon,
|
||||
.dplayer-play-icon {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ class Comment {
|
|||
|
||||
// text can't be empty
|
||||
if (!this.player.template.commentInput.value.replace(/^\s+|\s+$/g, '')) {
|
||||
this.player.notice(this.player.tran('please-input-danmaku'));
|
||||
this.player.notice(this.player.tran('Please input danmaku content!'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class ContextMenu {
|
|||
}
|
||||
});
|
||||
|
||||
this.contextmenuHandler = (e) => {
|
||||
this.player.container.addEventListener('contextmenu', (e) => {
|
||||
if (this.shown) {
|
||||
this.hide();
|
||||
return;
|
||||
|
|
@ -27,8 +27,7 @@ class ContextMenu {
|
|||
this.player.template.mask.addEventListener('click', () => {
|
||||
this.hide();
|
||||
});
|
||||
};
|
||||
this.player.container.addEventListener('contextmenu', this.contextmenuHandler);
|
||||
});
|
||||
}
|
||||
|
||||
show(x, y) {
|
||||
|
|
@ -63,10 +62,6 @@ class ContextMenu {
|
|||
this.shown = false;
|
||||
this.player.events.trigger('contextmenu_hide');
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.player.container.removeEventListener('contextmenu', this.contextmenuHandler);
|
||||
}
|
||||
}
|
||||
|
||||
export default ContextMenu;
|
||||
|
|
|
|||
|
|
@ -2,21 +2,24 @@ import utils from './utils';
|
|||
import Thumbnails from './thumbnails';
|
||||
import Icons from './icons';
|
||||
|
||||
let cast;
|
||||
let runOnce = true;
|
||||
let isCasting = false;
|
||||
|
||||
class Controller {
|
||||
constructor(player) {
|
||||
this.player = player;
|
||||
|
||||
this.autoHideTimer = 0;
|
||||
if (!utils.isMobile) {
|
||||
this.setAutoHideHandler = this.setAutoHide.bind(this);
|
||||
this.player.container.addEventListener('mousemove', this.setAutoHideHandler);
|
||||
this.player.container.addEventListener('click', this.setAutoHideHandler);
|
||||
this.player.on('play', this.setAutoHideHandler);
|
||||
this.player.on('pause', this.setAutoHideHandler);
|
||||
this.player.container.addEventListener('mousemove', () => {
|
||||
this.setAutoHide();
|
||||
});
|
||||
this.player.container.addEventListener('click', () => {
|
||||
this.setAutoHide();
|
||||
});
|
||||
this.player.on('play', () => {
|
||||
this.setAutoHide();
|
||||
});
|
||||
this.player.on('pause', () => {
|
||||
this.setAutoHide();
|
||||
});
|
||||
}
|
||||
|
||||
this.initPlayButton();
|
||||
|
|
@ -25,15 +28,11 @@ class Controller {
|
|||
this.initFullButton();
|
||||
this.initQualityButton();
|
||||
this.initScreenshotButton();
|
||||
// if subtitle url not array, not init old single subtitle button
|
||||
if (this.player.options.subtitle) {
|
||||
if (typeof this.player.options.subtitle.url === 'string') {
|
||||
this.initSubtitleButton();
|
||||
}
|
||||
}
|
||||
this.initSubtitleButton();
|
||||
this.initHighlights();
|
||||
this.initAirplayButton();
|
||||
this.initChromecastButton();
|
||||
if (utils.isSafari) {
|
||||
this.initAirplayButton();
|
||||
}
|
||||
if (!utils.isMobile) {
|
||||
this.initVolumeButton();
|
||||
}
|
||||
|
|
@ -49,14 +48,12 @@ class Controller {
|
|||
});
|
||||
|
||||
if (!utils.isMobile) {
|
||||
if (!this.player.options.preventClickToggle) {
|
||||
this.player.template.videoWrap.addEventListener('click', () => {
|
||||
this.player.toggle();
|
||||
});
|
||||
this.player.template.controllerMask.addEventListener('click', () => {
|
||||
this.player.toggle();
|
||||
});
|
||||
}
|
||||
this.player.template.videoWrap.addEventListener('click', () => {
|
||||
this.player.toggle();
|
||||
});
|
||||
this.player.template.controllerMask.addEventListener('click', () => {
|
||||
this.player.toggle();
|
||||
});
|
||||
} else {
|
||||
this.player.template.videoWrap.addEventListener('click', () => {
|
||||
this.toggle();
|
||||
|
|
@ -71,7 +68,7 @@ class Controller {
|
|||
this.player.on('durationchange', () => {
|
||||
if (this.player.video.duration !== 1 && this.player.video.duration !== Infinity) {
|
||||
if (this.player.options.highlight) {
|
||||
const highlights = this.player.template.playedBarWrap.querySelectorAll('.dplayer-highlight');
|
||||
const highlights = document.querySelectorAll('.dplayer-highlight');
|
||||
[].slice.call(highlights, 0).forEach((item) => {
|
||||
this.player.template.playedBarWrap.removeChild(item);
|
||||
});
|
||||
|
|
@ -122,11 +119,11 @@ class Controller {
|
|||
percentage = Math.min(percentage, 1);
|
||||
this.player.bar.set('played', percentage, 'width');
|
||||
this.player.seek(this.player.bar.get('played') * this.player.video.duration);
|
||||
this.player.moveBar = false;
|
||||
this.player.timer.enable('progress');
|
||||
};
|
||||
|
||||
this.player.template.playedBarWrap.addEventListener(utils.nameMap.dragStart, () => {
|
||||
this.player.moveBar = true;
|
||||
this.player.timer.disable('progress');
|
||||
document.addEventListener(utils.nameMap.dragMove, thumbMove);
|
||||
document.addEventListener(utils.nameMap.dragEnd, thumbUp);
|
||||
});
|
||||
|
|
@ -248,8 +245,9 @@ class Controller {
|
|||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(dataURL);
|
||||
this.player.events.trigger('screenshot', dataURL);
|
||||
});
|
||||
|
||||
this.player.events.trigger('screenshot', dataURL);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -283,103 +281,25 @@ class Controller {
|
|||
}
|
||||
}
|
||||
|
||||
initChromecast() {
|
||||
const script = window.document.createElement('script');
|
||||
script.setAttribute('type', 'text/javascript');
|
||||
script.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1');
|
||||
window.document.body.appendChild(script);
|
||||
initSubtitleButton() {
|
||||
if (this.player.options.subtitle) {
|
||||
this.player.events.on('subtitle_show', () => {
|
||||
this.player.template.subtitleButton.dataset.balloon = this.player.tran('Hide subtitle');
|
||||
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 subtitle');
|
||||
this.player.template.subtitleButtonInner.style.opacity = '0.4';
|
||||
this.player.user.set('subtitle', 0);
|
||||
});
|
||||
|
||||
window.__onGCastApiAvailable = (isAvailable) => {
|
||||
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();
|
||||
}
|
||||
this.player.template.subtitleButton.addEventListener('click', () => {
|
||||
this.player.subtitle.toggle();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
this.show();
|
||||
clearTimeout(this.autoHideTimer);
|
||||
|
|
@ -413,10 +333,6 @@ class Controller {
|
|||
}
|
||||
|
||||
destroy() {
|
||||
if (!utils.isMobile) {
|
||||
this.player.container.removeEventListener('mousemove', this.setAutoHideHandler);
|
||||
this.player.container.removeEventListener('click', this.setAutoHideHandler);
|
||||
}
|
||||
clearTimeout(this.autoHideTimer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import utils from './utils';
|
|||
class Danmaku {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
this.player = this.options.player;
|
||||
this.container = this.options.container;
|
||||
this.danTunnel = {
|
||||
right: {},
|
||||
|
|
@ -70,7 +69,7 @@ class Danmaku {
|
|||
}
|
||||
},
|
||||
error: (msg) => {
|
||||
this.options.error(msg || this.options.tran('danmaku-failed'));
|
||||
this.options.error(msg || this.options.tran('Danmaku load failed'));
|
||||
results[i] = [];
|
||||
|
||||
++readCount;
|
||||
|
|
@ -97,7 +96,7 @@ class Danmaku {
|
|||
data: danmakuData,
|
||||
success: callback,
|
||||
error: (msg) => {
|
||||
this.options.error(msg || this.options.tran('danmaku-failed'));
|
||||
this.options.error(msg || this.options.tran('Danmaku send failed'));
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -255,7 +254,6 @@ class Danmaku {
|
|||
if (tunnel >= 0) {
|
||||
// move
|
||||
item.classList.add('dplayer-danmaku-move');
|
||||
item.style.animationDuration = this._danAnimation(dan[i].type);
|
||||
|
||||
// insert
|
||||
docFragment.appendChild(item);
|
||||
|
|
@ -309,7 +307,13 @@ class Danmaku {
|
|||
}
|
||||
|
||||
htmlEncode(str) {
|
||||
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/');
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/\//g, '/');
|
||||
}
|
||||
|
||||
resize() {
|
||||
|
|
@ -339,21 +343,6 @@ class Danmaku {
|
|||
unlimit(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;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class FullScreen {
|
|||
utils.setScrollPosition(this.lastScrollPosition);
|
||||
});
|
||||
|
||||
this.fullscreenchange = () => {
|
||||
const fullscreenchange = () => {
|
||||
this.player.resize();
|
||||
if (this.isFullScreen('browser')) {
|
||||
this.player.events.trigger('fullscreen');
|
||||
|
|
@ -21,7 +21,7 @@ class FullScreen {
|
|||
this.player.events.trigger('fullscreen_cancel');
|
||||
}
|
||||
};
|
||||
this.docfullscreenchange = () => {
|
||||
const docfullscreenchange = () => {
|
||||
const fullEle = document.fullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
|
||||
if (fullEle && fullEle !== this.player.container) {
|
||||
return;
|
||||
|
|
@ -35,13 +35,13 @@ class FullScreen {
|
|||
}
|
||||
};
|
||||
if (/Firefox/.test(navigator.userAgent)) {
|
||||
document.addEventListener('mozfullscreenchange', this.docfullscreenchange);
|
||||
document.addEventListener('fullscreenchange', this.docfullscreenchange);
|
||||
document.addEventListener('mozfullscreenchange', docfullscreenchange);
|
||||
document.addEventListener('fullscreenchange', docfullscreenchange);
|
||||
} else {
|
||||
this.player.container.addEventListener('fullscreenchange', this.fullscreenchange);
|
||||
this.player.container.addEventListener('webkitfullscreenchange', this.fullscreenchange);
|
||||
document.addEventListener('msfullscreenchange', this.docfullscreenchange);
|
||||
document.addEventListener('MSFullscreenChange', this.docfullscreenchange);
|
||||
this.player.container.addEventListener('fullscreenchange', fullscreenchange);
|
||||
this.player.container.addEventListener('webkitfullscreenchange', fullscreenchange);
|
||||
document.addEventListener('msfullscreenchange', docfullscreenchange);
|
||||
document.addEventListener('MSFullscreenChange', docfullscreenchange);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,18 +122,6 @@ class FullScreen {
|
|||
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;
|
||||
|
|
|
|||
118
src/js/hotkey.js
118
src/js/hotkey.js
|
|
@ -1,74 +1,60 @@
|
|||
class HotKey {
|
||||
constructor(player) {
|
||||
this.player = player;
|
||||
this.doHotKeyHandler = this.doHotKey.bind(this);
|
||||
this.cancelFullScreenHandler = this.cancelFullScreen.bind(this);
|
||||
if (this.player.options.hotkey) {
|
||||
document.addEventListener('keydown', this.doHotKeyHandler);
|
||||
if (player.options.hotkey) {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (player.focus) {
|
||||
const tag = document.activeElement.tagName.toUpperCase();
|
||||
const editable = document.activeElement.getAttribute('contenteditable');
|
||||
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', this.cancelFullScreenHandler);
|
||||
}
|
||||
|
||||
doHotKey(e) {
|
||||
if (this.player.focus) {
|
||||
const tag = document.activeElement.tagName.toUpperCase();
|
||||
const editable = document.activeElement.getAttribute('contenteditable');
|
||||
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;
|
||||
}
|
||||
document.addEventListener('keydown', (e) => {
|
||||
const event = e || window.event;
|
||||
switch (event.keyCode) {
|
||||
case 27:
|
||||
if (player.fullScreen.isFullScreen('web')) {
|
||||
player.fullScreen.cancel('web');
|
||||
}
|
||||
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,358 +9,97 @@ Use this as shown below..... */
|
|||
|
||||
function i18n(lang) {
|
||||
this.lang = lang;
|
||||
// in case someone says en-us, and en is present!
|
||||
this.fallbackLang = this.lang.includes('-') ? this.lang.split('-')[0] : this.lang;
|
||||
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];
|
||||
this.tran = (text) => {
|
||||
if (tranTxt[this.lang] && tranTxt[this.lang][text]) {
|
||||
return tranTxt[this.lang][text];
|
||||
} else {
|
||||
return key;
|
||||
return text;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 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
|
||||
const tranTxt = {
|
||||
en: standard,
|
||||
'zh-cn': {
|
||||
'danmaku-loading': '弹幕加载中',
|
||||
top: '顶部',
|
||||
bottom: '底部',
|
||||
rolling: '滚动',
|
||||
'input-danmaku-enter': '输入弹幕,回车发送',
|
||||
'about-author': '关于作者',
|
||||
'dplayer-feedback': '播放器意见反馈',
|
||||
'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 画质',
|
||||
ff: '快进 %s 秒',
|
||||
rew: '快退 %s 秒',
|
||||
'unlimited-danmaku': '海量弹幕',
|
||||
'send-danmaku': '发送弹幕',
|
||||
setting: '设置',
|
||||
fullscreen: '全屏',
|
||||
'web-fullscreen': '页面全屏',
|
||||
send: '发送',
|
||||
screenshot: '截图',
|
||||
airplay: '无线投屏',
|
||||
chromecast: 'ChromeCast',
|
||||
subtitle: '字幕',
|
||||
off: '关闭',
|
||||
'show-subs': '显示字幕',
|
||||
'hide-subs': '隐藏字幕',
|
||||
volume: '音量',
|
||||
live: '直播',
|
||||
'video-info': '视频统计信息',
|
||||
'Danmaku is loading': '弹幕加载中',
|
||||
Top: '顶部',
|
||||
Bottom: '底部',
|
||||
Rolling: '滚动',
|
||||
'Input danmaku, hit Enter': '输入弹幕,回车发送',
|
||||
'About author': '关于作者',
|
||||
'DPlayer feedback': '播放器意见反馈',
|
||||
'About DPlayer': '关于 DPlayer 播放器',
|
||||
Loop: '洗脑循环',
|
||||
Speed: '速度',
|
||||
'Opacity for danmaku': '弹幕透明度',
|
||||
Normal: '正常',
|
||||
'Please input danmaku content!': '要输入弹幕内容啊喂!',
|
||||
'Set danmaku color': '设置弹幕颜色',
|
||||
'Set danmaku type': '设置弹幕类型',
|
||||
'Show danmaku': '显示弹幕',
|
||||
'Video load failed': '视频加载失败',
|
||||
'Danmaku load failed': '弹幕加载失败',
|
||||
'Danmaku send failed': '弹幕发送失败',
|
||||
'Switching to': '正在切换至',
|
||||
'Switched to': '已经切换至',
|
||||
quality: '画质',
|
||||
FF: '快进',
|
||||
REW: '快退',
|
||||
'Unlimited danmaku': '海量弹幕',
|
||||
'Send danmaku': '发送弹幕',
|
||||
Setting: '设置',
|
||||
'Full screen': '全屏',
|
||||
'Web full screen': '页面全屏',
|
||||
Send: '发送',
|
||||
Screenshot: '截图',
|
||||
AirPlay: '无线投屏',
|
||||
s: '秒',
|
||||
'Show subtitle': '显示字幕',
|
||||
'Hide subtitle': '隐藏字幕',
|
||||
Volume: '音量',
|
||||
Live: '直播',
|
||||
'Video info': '视频统计信息',
|
||||
},
|
||||
'zh-tw': {
|
||||
'danmaku-loading': '彈幕載入中',
|
||||
top: '頂部',
|
||||
bottom: '底部',
|
||||
rolling: '滾動',
|
||||
'input-danmaku-enter': '輸入彈幕,Enter 發送',
|
||||
'about-author': '關於作者',
|
||||
'dplayer-feedback': '播放器意見回饋',
|
||||
'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 畫質',
|
||||
ff: '快進 %s 秒',
|
||||
rew: '快退 %s 秒',
|
||||
'unlimited-danmaku': '巨量彈幕',
|
||||
'send-danmaku': '發送彈幕',
|
||||
setting: '設定',
|
||||
fullscreen: '全螢幕',
|
||||
'web-fullscreen': '頁面全螢幕',
|
||||
send: '發送',
|
||||
screenshot: '截圖',
|
||||
airplay: '無線投屏',
|
||||
chromecast: 'ChromeCast',
|
||||
subtitle: '字幕',
|
||||
off: '關閉',
|
||||
'show-subs': '顯示字幕',
|
||||
'hide-subs': '隱藏字幕',
|
||||
volume: '音量',
|
||||
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': 'Информация о видео',
|
||||
'Danmaku is loading': '彈幕載入中',
|
||||
Top: '頂部',
|
||||
Bottom: '底部',
|
||||
Rolling: '滾動',
|
||||
'Input danmaku, hit Enter': '輸入彈幕,Enter 發送',
|
||||
'About author': '關於作者',
|
||||
'DPlayer feedback': '播放器意見回饋',
|
||||
'About DPlayer': '關於 DPlayer 播放器',
|
||||
Loop: '循環播放',
|
||||
Speed: '速度',
|
||||
'Opacity for danmaku': '彈幕透明度',
|
||||
Normal: '正常',
|
||||
'Please input danmaku content!': '請輸入彈幕內容啊!',
|
||||
'Set danmaku color': '設定彈幕顏色',
|
||||
'Set danmaku type': '設定彈幕類型',
|
||||
'Show danmaku': '顯示彈幕',
|
||||
'Video load failed': '影片載入失敗',
|
||||
'Danmaku load failed': '彈幕載入失敗',
|
||||
'Danmaku send failed': '彈幕發送失敗',
|
||||
'Switching to': '正在切換至',
|
||||
'Switched to': '已經切換至',
|
||||
quality: '畫質',
|
||||
FF: '快進',
|
||||
REW: '快退',
|
||||
'Unlimited danmaku': '巨量彈幕',
|
||||
'Send danmaku': '發送彈幕',
|
||||
Setting: '設定',
|
||||
'Full screen': '全螢幕',
|
||||
'Web full screen': '頁面全螢幕',
|
||||
Send: '發送',
|
||||
Screenshot: '截圖',
|
||||
AirPlay: '無線投屏',
|
||||
s: '秒',
|
||||
'Show subtitle': '顯示字幕',
|
||||
'Hide subtitle': '隱藏字幕',
|
||||
Volume: '音量',
|
||||
Live: '直播',
|
||||
'Video info': '影片統計訊息',
|
||||
},
|
||||
};
|
||||
|
||||
export { i18n };
|
||||
export default i18n;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import camera from '../assets/camera.svg';
|
|||
import airplay from '../assets/airplay.svg';
|
||||
import subtitle from '../assets/subtitle.svg';
|
||||
import loading from '../assets/loading.svg';
|
||||
import chromecast from '../assets/chromecast.svg';
|
||||
|
||||
const Icons = {
|
||||
play: play,
|
||||
|
|
@ -35,7 +34,6 @@ const Icons = {
|
|||
subtitle: subtitle,
|
||||
loading: loading,
|
||||
airplay: airplay,
|
||||
chromecast: chromecast,
|
||||
};
|
||||
|
||||
export default Icons;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import '../css/index.less';
|
||||
import '../css/index.scss';
|
||||
import DPlayer from './player';
|
||||
|
||||
/* global DPLAYER_VERSION GIT_HASH */
|
||||
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;');
|
||||
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;');
|
||||
|
||||
export default DPlayer;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export default (options) => {
|
|||
lang: (navigator.language || navigator.browserLanguage).toLowerCase(),
|
||||
screenshot: false,
|
||||
airplay: true,
|
||||
chromecast: false,
|
||||
hotkey: true,
|
||||
preload: 'metadata',
|
||||
volume: 0.7,
|
||||
|
|
@ -22,7 +21,6 @@ export default (options) => {
|
|||
contextmenu: [],
|
||||
mutex: true,
|
||||
pluginOptions: { hls: {}, flv: {}, dash: {}, webtorrent: {} },
|
||||
preventClickToggle: false,
|
||||
};
|
||||
for (const defaultKey in defaultOption) {
|
||||
if (defaultOption.hasOwnProperty(defaultKey) && !options.hasOwnProperty(defaultKey)) {
|
||||
|
|
@ -52,13 +50,13 @@ export default (options) => {
|
|||
|
||||
options.contextmenu = options.contextmenu.concat([
|
||||
{
|
||||
key: 'video-info',
|
||||
text: 'Video info',
|
||||
click: (player) => {
|
||||
player.infoPanel.triggle();
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'about-author',
|
||||
text: 'About author',
|
||||
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 handleOption from './options';
|
||||
import { i18n } from './i18n';
|
||||
import i18n from './i18n';
|
||||
import Template from './template';
|
||||
import Icons from './icons';
|
||||
import Danmaku from './danmaku';
|
||||
|
|
@ -10,7 +10,6 @@ import Events from './events';
|
|||
import FullScreen from './fullscreen';
|
||||
import User from './user';
|
||||
import Subtitle from './subtitle';
|
||||
import Subtitles from './subtitles';
|
||||
import Bar from './bar';
|
||||
import Timer from './timer';
|
||||
import Bezel from './bezel';
|
||||
|
|
@ -43,7 +42,6 @@ class DPlayer {
|
|||
this.events = new Events();
|
||||
this.user = new User(this);
|
||||
this.container = this.options.container;
|
||||
this.noticeList = {};
|
||||
|
||||
this.container.classList.add('dplayer');
|
||||
if (!this.options.danmaku) {
|
||||
|
|
@ -51,8 +49,6 @@ class DPlayer {
|
|||
}
|
||||
if (this.options.live) {
|
||||
this.container.classList.add('dplayer-live');
|
||||
} else {
|
||||
this.container.classList.remove('dplayer-live');
|
||||
}
|
||||
if (utils.isMobile) {
|
||||
this.container.classList.add('dplayer-mobile');
|
||||
|
|
@ -62,43 +58,6 @@ class DPlayer {
|
|||
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({
|
||||
container: this.container,
|
||||
options: this.options,
|
||||
|
|
@ -118,7 +77,6 @@ class DPlayer {
|
|||
|
||||
if (this.options.danmaku) {
|
||||
this.danmaku = new Danmaku({
|
||||
player: this,
|
||||
container: this.template.danmaku,
|
||||
opacity: this.user.get('opacity'),
|
||||
callback: () => {
|
||||
|
|
@ -146,7 +104,6 @@ class DPlayer {
|
|||
maximum: this.options.danmaku.maximum,
|
||||
addition: this.options.danmaku.addition,
|
||||
user: this.options.danmaku.user,
|
||||
speedRate: this.options.danmaku.speedRate,
|
||||
},
|
||||
events: this.events,
|
||||
tran: (msg) => this.tran(msg),
|
||||
|
|
@ -157,14 +114,21 @@ class DPlayer {
|
|||
|
||||
this.setting = new Setting(this);
|
||||
this.plugins = {};
|
||||
this.docClickFun = () => {
|
||||
this.focus = false;
|
||||
};
|
||||
this.containerClickFun = () => {
|
||||
this.focus = true;
|
||||
};
|
||||
document.addEventListener('click', this.docClickFun, true);
|
||||
this.container.addEventListener('click', this.containerClickFun, true);
|
||||
|
||||
document.addEventListener(
|
||||
'click',
|
||||
() => {
|
||||
this.focus = false;
|
||||
},
|
||||
true
|
||||
);
|
||||
this.container.addEventListener(
|
||||
'click',
|
||||
() => {
|
||||
this.focus = true;
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
this.paused = true;
|
||||
|
||||
|
|
@ -182,8 +146,6 @@ class DPlayer {
|
|||
this.play();
|
||||
}
|
||||
|
||||
this.moveBar = false;
|
||||
|
||||
index++;
|
||||
instances.push(this);
|
||||
}
|
||||
|
|
@ -197,9 +159,9 @@ class DPlayer {
|
|||
time = Math.min(time, this.video.duration);
|
||||
}
|
||||
if (this.video.currentTime < time) {
|
||||
this.notice(`${this.tran('ff').replace('%s', (time - this.video.currentTime).toFixed(0))}`);
|
||||
this.notice(`${this.tran('FF')} ${(time - this.video.currentTime).toFixed(0)} ${this.tran('s')}`);
|
||||
} else if (this.video.currentTime > time) {
|
||||
this.notice(`${this.tran('rew').replace('%s', (this.video.currentTime - time).toFixed(0))}`);
|
||||
this.notice(`${this.tran('REW')} ${(this.video.currentTime - time).toFixed(0)} ${this.tran('s')}`);
|
||||
}
|
||||
|
||||
this.video.currentTime = time;
|
||||
|
|
@ -296,7 +258,7 @@ class DPlayer {
|
|||
this.user.set('volume', percentage);
|
||||
}
|
||||
if (!nonotice) {
|
||||
this.notice(`${this.tran('volume')} ${(percentage * 100).toFixed(0)}%`, undefined, undefined, 'volume');
|
||||
this.notice(`${this.tran('Volume')} ${(percentage * 100).toFixed(0)}%`);
|
||||
}
|
||||
|
||||
this.video.volume = percentage;
|
||||
|
|
@ -382,7 +344,6 @@ class DPlayer {
|
|||
this.type = 'normal';
|
||||
}
|
||||
|
||||
const src = this.quality.url; // 真实的视频 url, 用于切换清晰度时销毁实例
|
||||
switch (this.type) {
|
||||
// https://github.com/video-dev/hls.js
|
||||
case 'hls':
|
||||
|
|
@ -397,12 +358,6 @@ class DPlayer {
|
|||
hls.destroy();
|
||||
delete this.plugins.hls;
|
||||
});
|
||||
// 切换清晰度时销毁实例
|
||||
this.events.on('quality_end', () => {
|
||||
if (src !== this.quality.url) {
|
||||
hls.destroy();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.notice('Error: Hls is not supported.');
|
||||
}
|
||||
|
|
@ -431,14 +386,6 @@ class DPlayer {
|
|||
flvPlayer.destroy();
|
||||
delete this.plugins.flvjs;
|
||||
});
|
||||
// 切换清晰度时销毁实例
|
||||
this.events.on('quality_end', () => {
|
||||
if (src !== this.quality.url) {
|
||||
flvPlayer.unload();
|
||||
flvPlayer.detachMediaElement();
|
||||
flvPlayer.destroy();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.notice('Error: flvjs is not supported.');
|
||||
}
|
||||
|
|
@ -450,8 +397,7 @@ class DPlayer {
|
|||
// https://github.com/Dash-Industry-Forum/dash.js
|
||||
case 'dash':
|
||||
if (window.dashjs) {
|
||||
const dashjsPlayer = window.dashjs.MediaPlayer().create();
|
||||
dashjsPlayer.initialize(video, video.src, false, 0);
|
||||
const dashjsPlayer = window.dashjs.MediaPlayer().create().initialize(video, video.src, false);
|
||||
const options = this.options.pluginOptions.dash;
|
||||
dashjsPlayer.updateSettings(options);
|
||||
this.plugins.dash = dashjsPlayer;
|
||||
|
|
@ -459,12 +405,6 @@ class DPlayer {
|
|||
window.dashjs.MediaPlayer().reset();
|
||||
delete this.plugins.dash;
|
||||
});
|
||||
// 切换清晰度时销毁实例
|
||||
this.events.on('quality_end', () => {
|
||||
if (src !== this.quality.url) {
|
||||
window.dashjs.MediaPlayer().reset();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.notice("Error: Can't find dashjs.");
|
||||
}
|
||||
|
|
@ -494,13 +434,6 @@ class DPlayer {
|
|||
client.destroy();
|
||||
delete this.plugins.webtorrent;
|
||||
});
|
||||
// 切换清晰度时销毁实例
|
||||
this.events.on('quality_end', () => {
|
||||
if (src !== this.quality.url) {
|
||||
client.remove(torrentId);
|
||||
client.destroy();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.notice('Error: Webtorrent is not supported.');
|
||||
}
|
||||
|
|
@ -538,7 +471,7 @@ class DPlayer {
|
|||
// Not a video load error, may be poster load failed, see #307
|
||||
return;
|
||||
}
|
||||
this.tran && this.notice && this.type !== 'webtorrent' && this.notice(this.tran('video-failed'));
|
||||
this.tran && this.notice && this.type !== 'webtorrent' && this.notice(this.tran('Video load failed'), -1);
|
||||
});
|
||||
|
||||
// video end
|
||||
|
|
@ -568,9 +501,7 @@ class DPlayer {
|
|||
});
|
||||
|
||||
this.on('timeupdate', () => {
|
||||
if (!this.moveBar) {
|
||||
this.bar.set('played', this.video.currentTime / this.video.duration, 'width');
|
||||
}
|
||||
this.bar.set('played', this.video.currentTime / this.video.duration, 'width');
|
||||
const currentTime = utils.secondToTime(this.video.currentTime);
|
||||
if (this.template.ptime.innerHTML !== currentTime) {
|
||||
this.template.ptime.innerHTML = currentTime;
|
||||
|
|
@ -578,20 +509,15 @@ class DPlayer {
|
|||
});
|
||||
|
||||
for (let i = 0; i < this.events.videoEvents.length; i++) {
|
||||
video.addEventListener(this.events.videoEvents[i], (e) => {
|
||||
this.events.trigger(this.events.videoEvents[i], e);
|
||||
video.addEventListener(this.events.videoEvents[i], () => {
|
||||
this.events.trigger(this.events.videoEvents[i]);
|
||||
});
|
||||
}
|
||||
|
||||
this.volume(this.user.get('volume'), true, true);
|
||||
|
||||
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);
|
||||
// init multi subtitles function(sub update)
|
||||
if (Array.isArray(this.options.subtitle.url)) {
|
||||
this.subtitles = new Subtitles(this);
|
||||
}
|
||||
if (!this.user.get('subtitle')) {
|
||||
this.subtitle.hide();
|
||||
}
|
||||
|
|
@ -603,7 +529,6 @@ class DPlayer {
|
|||
if (this.qualityIndex === index || this.switchingQuality) {
|
||||
return;
|
||||
} else {
|
||||
this.prevIndex = this.qualityIndex;
|
||||
this.qualityIndex = index;
|
||||
}
|
||||
this.switchingQuality = true;
|
||||
|
|
@ -626,7 +551,7 @@ class DPlayer {
|
|||
this.video = videoEle;
|
||||
this.initVideo(this.video, this.quality.type || this.options.video.type);
|
||||
this.seek(this.prevVideo.currentTime);
|
||||
this.notice(`${this.tran('switching-quality').replace('%q', this.quality.name)}`, -1, undefined, 'switch-quality');
|
||||
this.notice(`${this.tran('Switching to')} ${this.quality.name} ${this.tran('quality')}`, -1);
|
||||
this.events.trigger('quality_start', this.quality);
|
||||
|
||||
this.on('canplay', () => {
|
||||
|
|
@ -641,69 +566,26 @@ class DPlayer {
|
|||
this.video.play();
|
||||
}
|
||||
this.prevVideo = null;
|
||||
this.notice(`${this.tran('switched-quality').replace('%q', this.quality.name)}`, undefined, undefined, 'switch-quality');
|
||||
this.notice(`${this.tran('Switched to')} ${this.quality.name} ${this.tran('quality')}`);
|
||||
this.switchingQuality = false;
|
||||
|
||||
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, id) {
|
||||
let oldNoticeEle;
|
||||
if (id) {
|
||||
oldNoticeEle = document.getElementById(`dplayer-notice-${id}`);
|
||||
if (oldNoticeEle) {
|
||||
oldNoticeEle.innerHTML = text;
|
||||
}
|
||||
if (this.noticeList[id]) {
|
||||
clearTimeout(this.noticeList[id]);
|
||||
this.noticeList[id] = null;
|
||||
}
|
||||
notice(text, time = 2000, opacity = 0.8) {
|
||||
this.template.notice.innerHTML = text;
|
||||
this.template.notice.style.opacity = opacity;
|
||||
if (this.noticeTime) {
|
||||
clearTimeout(this.noticeTime);
|
||||
}
|
||||
if (!oldNoticeEle) {
|
||||
const notice = Template.NewNotice(text, opacity, id);
|
||||
this.template.noticeList.appendChild(notice);
|
||||
oldNoticeEle = notice;
|
||||
}
|
||||
|
||||
this.events.trigger('notice_show', oldNoticeEle);
|
||||
|
||||
this.events.trigger('notice_show', text);
|
||||
if (time > 0) {
|
||||
this.noticeList[id] = setTimeout(
|
||||
(function (e, dp) {
|
||||
return () => {
|
||||
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
|
||||
);
|
||||
this.noticeTime = setTimeout(() => {
|
||||
this.template.notice.style.opacity = 0;
|
||||
this.events.trigger('notice_hide');
|
||||
}, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -724,11 +606,6 @@ class DPlayer {
|
|||
destroy() {
|
||||
instances.splice(instances.indexOf(this), 1);
|
||||
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.timer.destroy();
|
||||
this.video.src = '';
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class Subtitle {
|
|||
const track = this.video.textTracks[0];
|
||||
|
||||
track.oncuechange = () => {
|
||||
const cue = track.activeCues[track.activeCues.length - 1];
|
||||
const cue = track.activeCues[0];
|
||||
this.container.innerHTML = '';
|
||||
if (cue) {
|
||||
const template = document.createElement('div');
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
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,8 +22,7 @@ class Template {
|
|||
current: true,
|
||||
pic: this.options.video.pic,
|
||||
screenshot: this.options.screenshot,
|
||||
airplay: utils.isSafari && !utils.isChrome ? this.options.airplay : false,
|
||||
chromecast: this.options.chromecast,
|
||||
airplay: this.options.airplay,
|
||||
preload: this.options.preload,
|
||||
url: this.options.video.url,
|
||||
subtitle: this.options.subtitle,
|
||||
|
|
@ -81,18 +80,13 @@ class Template {
|
|||
this.qualityList = this.container.querySelector('.dplayer-quality-list');
|
||||
this.camareButton = this.container.querySelector('.dplayer-camera-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.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.subtrack = this.container.querySelector('.dplayer-subtrack');
|
||||
this.qualityButton = this.container.querySelector('.dplayer-quality-icon');
|
||||
this.barPreview = this.container.querySelector('.dplayer-bar-preview');
|
||||
this.barWrap = this.container.querySelector('.dplayer-bar-wrap');
|
||||
this.noticeList = this.container.querySelector('.dplayer-notice-list');
|
||||
this.notice = this.container.querySelector('.dplayer-notice');
|
||||
this.infoPanel = this.container.querySelector('.dplayer-info-panel');
|
||||
this.infoPanelClose = this.container.querySelector('.dplayer-info-panel-close');
|
||||
this.infoVersion = this.container.querySelector('.dplayer-info-panel-item-version .dplayer-info-panel-item-data');
|
||||
|
|
@ -105,17 +99,6 @@ class Template {
|
|||
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');
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class Timer {
|
|||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function (callback) {
|
||||
function(callback) {
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
})();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
const isMobile = /mobile|android|iphone|ipod|phone|ipad/i.test(window.navigator.userAgent);
|
||||
const isMobile = /mobile/i.test(window.navigator.userAgent);
|
||||
|
||||
const isSafari = /Safari/i.test(window.navigator.userAgent);
|
||||
|
||||
const utils = {
|
||||
/**
|
||||
|
|
@ -89,12 +91,12 @@ const utils = {
|
|||
|
||||
isMobile: isMobile,
|
||||
|
||||
isSafari: isSafari,
|
||||
|
||||
isFirefox: /firefox/i.test(window.navigator.userAgent),
|
||||
|
||||
isChrome: /chrome/i.test(window.navigator.userAgent),
|
||||
|
||||
isSafari: /safari/i.test(window.navigator.userAgent),
|
||||
|
||||
storage: {
|
||||
set: (key, value) => {
|
||||
localStorage.setItem(key, value);
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
<img src="{{ options.logo }}">
|
||||
</div>
|
||||
{{ /if }}
|
||||
<div class="dplayer-danmaku"{{ if options.danmaku && options.danmaku.bottom }} style="margin-bottom:{{ options.danmaku.bottom }}"{{ /if }}>
|
||||
<div class="dplayer-danmaku"{{ if options.danmaku && options.danmaku.bottm }} style="margin-bottom:{{ options.danmaku.bottm }}"{{ /if }}>
|
||||
<div class="dplayer-danmaku-item dplayer-danmaku-item--demo"></div>
|
||||
</div>
|
||||
<div class="dplayer-subtitle"></div>
|
||||
<div class="dplayer-bezel">
|
||||
<span class="dplayer-bezel-icon"></span>
|
||||
{{ if options.danmaku }}
|
||||
<span class="dplayer-danloading">{{ tran('danmaku-loading') }}</span>
|
||||
<span class="dplayer-danloading">{{ tran('Danmaku is loading') }}</span>
|
||||
{{ /if }}
|
||||
<span class="diplayer-loading-icon">{{@ icons.loading }}</span>
|
||||
</div>
|
||||
|
|
@ -21,12 +21,12 @@
|
|||
<div class="dplayer-controller-mask"></div>
|
||||
<div class="dplayer-controller">
|
||||
<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>
|
||||
</button>
|
||||
<div class="dplayer-comment-setting-box">
|
||||
<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>
|
||||
<input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#fff" checked>
|
||||
<span style="background: #fff;"></span>
|
||||
|
|
@ -53,23 +53,23 @@
|
|||
</label>
|
||||
</div>
|
||||
<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>
|
||||
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="1">
|
||||
<span>{{ tran('top') }}</span>
|
||||
<span>{{ tran('Top') }}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="0" checked>
|
||||
<span>{{ tran('rolling') }}</span>
|
||||
<span>{{ tran('Rolling') }}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="dplayer-danmaku-type-{{ index }}" value="2">
|
||||
<span>{{ tran('bottom') }}</span>
|
||||
<span>{{ tran('Bottom') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<input class="dplayer-comment-input" type="text" placeholder="{{ tran('Input danmaku, hit Enter') }}" maxlength="30">
|
||||
<button class="dplayer-icon dplayer-send-icon" data-balloon="{{ tran('Send') }}" data-balloon-pos="up">
|
||||
<span class="dplayer-icon-content">{{@ icons.send }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
<span class="dplayer-dtime">0:00</span>
|
||||
</span>
|
||||
{{ 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 }}
|
||||
</div>
|
||||
<div class="dplayer-icons dplayer-icons-right">
|
||||
|
|
@ -111,83 +111,60 @@
|
|||
</div>
|
||||
{{ /if }}
|
||||
{{ 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>
|
||||
</div>
|
||||
{{ /if }}
|
||||
{{ 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>
|
||||
</div>
|
||||
{{ /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">
|
||||
<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>
|
||||
</button>
|
||||
</div>
|
||||
{{ if options.subtitle }}
|
||||
{{ if (typeof options.subtitle.url === 'string') }}
|
||||
<div class="dplayer-subtitle-btn">
|
||||
<button class="dplayer-icon dplayer-subtitle-icon" data-balloon="{{ tran('hide-subs') }}" data-balloon-pos="up">
|
||||
<button class="dplayer-icon dplayer-subtitle-icon" data-balloon="{{ tran('Hide subtitle') }}" data-balloon-pos="up">
|
||||
<span class="dplayer-icon-content">{{@ icons.subtitle }}</span>
|
||||
</button>
|
||||
</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 }}
|
||||
<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>
|
||||
</button>
|
||||
<div class="dplayer-setting-box">
|
||||
<div class="dplayer-setting-origin-panel">
|
||||
<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>
|
||||
<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">
|
||||
<input class="dplayer-toggle-setting-input" type="checkbox" name="dplayer-toggle">
|
||||
<label for="dplayer-toggle"></label>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<input class="dplayer-showdan-setting-input" type="checkbox" name="dplayer-toggle-dan">
|
||||
<label for="dplayer-toggle-dan"></label>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<input class="dplayer-danunlimit-setting-input" type="checkbox" name="dplayer-toggle-danunlimit">
|
||||
<label for="dplayer-toggle-danunlimit"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dplayer-setting-item dplayer-setting-danmaku">
|
||||
<span class="dplayer-label">{{ tran('opacity-danmaku') }}</span>
|
||||
<span class="dplayer-label">{{ tran('Opacity for danmaku') }}</span>
|
||||
<div class="dplayer-danmaku-bar-wrap">
|
||||
<div class="dplayer-danmaku-bar">
|
||||
<div class="dplayer-danmaku-bar-inner">
|
||||
|
|
@ -200,17 +177,17 @@
|
|||
<div class="dplayer-setting-speed-panel">
|
||||
{{ each options.playbackSpeed }}
|
||||
<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>
|
||||
{{ /each }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dplayer-full">
|
||||
<button class="dplayer-icon dplayer-full-in-icon" data-balloon="{{ tran('web-fullscreen') }}" data-balloon-pos="up">
|
||||
<button class="dplayer-icon dplayer-full-in-icon" data-balloon="{{ tran('Web full screen') }}" data-balloon-pos="up">
|
||||
<span class="dplayer-icon-content">{{@ icons.fullWeb }}</span>
|
||||
</button>
|
||||
<button class="dplayer-icon dplayer-full-icon" data-balloon="{{ tran('fullscreen') }}" data-balloon-pos="up">
|
||||
<button class="dplayer-icon dplayer-full-icon" data-balloon="{{ tran('Full screen') }}" data-balloon-pos="up">
|
||||
<span class="dplayer-icon-content">{{@ icons.full }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -270,11 +247,11 @@
|
|||
<div class="dplayer-menu">
|
||||
{{ each options.contextmenu }}
|
||||
<div class="dplayer-menu-item">
|
||||
<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>
|
||||
<a{{ if $value.link }} target="_blank"{{ /if }} href="{{ $value.link || 'javascript:void(0);' }}">{{ tran($value.text) }}</a>
|
||||
</div>
|
||||
{{ /each }}
|
||||
</div>
|
||||
<div class="dplayer-notice-list"></div>
|
||||
<div class="dplayer-notice"></div>
|
||||
<button class="dplayer-mobile-play">
|
||||
{{@ icons.play }}
|
||||
</button>
|
||||
|
|
@ -7,16 +7,9 @@
|
|||
{{ if pic }}poster="{{ pic }}"{{ /if }}
|
||||
{{ if screenshot || enableSubtitle }}crossorigin="anonymous"{{ /if }}
|
||||
{{ if preload }}preload="{{ preload }}"{{ /if }}
|
||||
{{ if airplay }}
|
||||
nosrc
|
||||
{{ else if url }}
|
||||
src="{{ url }}"
|
||||
{{ /if }}
|
||||
{{ if url }}src="{{ url }}"{{ /if }}
|
||||
>
|
||||
{{ if airplay }}
|
||||
<source src="{{ url }}">
|
||||
{{ /if}}
|
||||
{{ if enableSubtitle }}
|
||||
<track class="dplayer-subtrack" kind="metadata" default src="{{ typeof subtitle.url === 'string' ? subtitle.url : subtitle.url[subtitle.index].url }}"></track>
|
||||
<track kind="metadata" default src="{{ subtitle.url }}"></track>
|
||||
{{ /if }}
|
||||
</video>
|
||||
6
tea.yaml
6
tea.yaml
|
|
@ -1,6 +0,0 @@
|
|||
# https://tea.xyz/what-is-this-file
|
||||
---
|
||||
version: 1.0.0
|
||||
codeOwners:
|
||||
- '0x185bfcef7b37010e2511309048a130f477f54fBf'
|
||||
quorum: 1
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const { GitRevisionPlugin } = require('git-revision-webpack-plugin');
|
||||
const GitRevisionPlugin = require('git-revision-webpack-plugin');
|
||||
const gitRevisionPlugin = new GitRevisionPlugin();
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const cssnano = require('cssnano');
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
|
|
@ -24,13 +26,7 @@ module.exports = {
|
|||
|
||||
resolve: {
|
||||
modules: ['node_modules'],
|
||||
extensions: ['.js', '.less'],
|
||||
fallback: {
|
||||
dgram: false,
|
||||
fs: false,
|
||||
net: false,
|
||||
tls: false,
|
||||
},
|
||||
extensions: ['.js', '.scss'],
|
||||
},
|
||||
|
||||
module: {
|
||||
|
|
@ -49,7 +45,7 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
|
|
@ -61,12 +57,10 @@ module.exports = {
|
|||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
postcssOptions: {
|
||||
plugins: ['postcss-preset-env'],
|
||||
},
|
||||
plugins: [autoprefixer, cssnano],
|
||||
},
|
||||
},
|
||||
'less-loader',
|
||||
'sass-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -88,11 +82,17 @@ module.exports = {
|
|||
},
|
||||
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.join(__dirname, '..', 'demo'),
|
||||
},
|
||||
compress: true,
|
||||
contentBase: path.resolve(__dirname, '..', 'demo'),
|
||||
clientLogLevel: 'none',
|
||||
quiet: false,
|
||||
open: true,
|
||||
historyApiFallback: {
|
||||
disableDotRule: true,
|
||||
},
|
||||
watchOptions: {
|
||||
ignored: /node_modules/,
|
||||
},
|
||||
},
|
||||
|
||||
plugins: [
|
||||
|
|
@ -102,6 +102,13 @@ module.exports = {
|
|||
}),
|
||||
],
|
||||
|
||||
node: {
|
||||
dgram: 'empty',
|
||||
fs: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty',
|
||||
},
|
||||
|
||||
performance: {
|
||||
hints: false,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const { GitRevisionPlugin } = require('git-revision-webpack-plugin');
|
||||
const GitRevisionPlugin = require('git-revision-webpack-plugin');
|
||||
const gitRevisionPlugin = new GitRevisionPlugin();
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const cssnano = require('cssnano');
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
|
|
@ -26,13 +28,7 @@ module.exports = {
|
|||
|
||||
resolve: {
|
||||
modules: ['node_modules'],
|
||||
extensions: ['.js', '.less'],
|
||||
fallback: {
|
||||
dgram: false,
|
||||
fs: false,
|
||||
net: false,
|
||||
tls: false,
|
||||
},
|
||||
extensions: ['.js', '.scss'],
|
||||
},
|
||||
|
||||
module: {
|
||||
|
|
@ -52,7 +48,7 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
|
|
@ -64,12 +60,10 @@ module.exports = {
|
|||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
postcssOptions: {
|
||||
plugins: ['postcss-preset-env'],
|
||||
},
|
||||
plugins: [autoprefixer, cssnano],
|
||||
},
|
||||
},
|
||||
'less-loader',
|
||||
'sass-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -96,4 +90,11 @@ module.exports = {
|
|||
GIT_HASH: JSON.stringify(gitRevisionPlugin.version()),
|
||||
}),
|
||||
],
|
||||
|
||||
node: {
|
||||
dgram: 'empty',
|
||||
fs: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue