Jelajahi Sumber

use art-template

DIYgod 7 tahun lalu
induk
melakukan
a16c948a2d
9 mengubah file dengan 418 tambahan dan 293 penghapusan
  1. 1 3
      demo/demo.js
  2. 2 0
      package.json
  3. 9 1
      src/js/player.js
  4. 15 287
      src/js/template.js
  5. 262 0
      src/template/player.art
  6. 14 0
      src/template/video.art
  7. 4 0
      webpack/dev.config.js
  8. 4 0
      webpack/prod.config.js
  9. 107 2
      yarn.lock

+ 1 - 3
demo/demo.js

@@ -64,9 +64,7 @@ function initPlayers () {
             token: 'tokendemo',
             maximum: 3000,
             user: 'DIYgod',
-            margin: {
-                bottom: '15%'
-            },
+            bottom: '15%',
             unlimited: true
         },
         contextmenu: [

+ 2 - 0
package.json

@@ -30,6 +30,8 @@
   },
   "homepage": "https://github.com/DIYgod/DPlayer#readme",
   "devDependencies": {
+    "art-template": "4.12.2",
+    "art-template-loader": "1.4.3",
     "autoprefixer": "^7.2.5",
     "babel-core": "^6.26.0",
     "babel-loader": "^7.1.2",

+ 9 - 1
src/js/player.js

@@ -19,6 +19,7 @@ import Comment from './comment';
 import HotKey from './hotkey';
 import ContextMenu from './contextmenu';
 import InfoPanel from './info-panel';
+import tplVideo from '../template/video.art';
 
 let index = 0;
 const instances = [];
@@ -492,7 +493,14 @@ class DPlayer {
 
         const paused = this.video.paused;
         this.video.pause();
-        const videoHTML = this.template.tplVideo(false, null, this.options.screenshot, 'auto', this.quality.url, this.options.subtitle);
+        const videoHTML = tplVideo({
+            current: false,
+            pic: null,
+            screenshot: this.options.screenshot,
+            preload: 'auto',
+            url: this.quality.url,
+            subtitle: this.options.subtitle
+        });
         const videoEle = new DOMParser().parseFromString(videoHTML, 'text/html').body.firstChild;
         this.template.videoWrap.insertBefore(videoEle, this.template.videoWrap.getElementsByTagName('div')[0]);
         this.prevVideo = this.video;

+ 15 - 287
src/js/template.js

@@ -1,4 +1,5 @@
 import Icons from './icons';
+import tplPlayer from '../template/player.art';
 
 class Template {
     constructor (options) {
@@ -10,7 +11,20 @@ class Template {
     }
 
     init () {
-        this.container.innerHTML = this.tpl(this.options, this.index, this.tran);
+        this.container.innerHTML = tplPlayer({
+            options: this.options,
+            index: this.index,
+            tran: this.tran,
+            icons: Icons,
+            video: {
+                current: true,
+                pic: this.options.video.pic,
+                screenshot: this.options.screenshot,
+                preload: this.options.preload,
+                url: this.options.video.url,
+                subtitle: this.options.subtitle
+            }
+        });
 
         this.volumeBar = this.container.querySelector('.dplayer-volume-bar-inner');
         this.volumeBarWrap = this.container.querySelector('.dplayer-volume-bar');
@@ -79,292 +93,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');
     }
-
-    tpl (options, index, tran) {
-        return `
-        <div class="dplayer-mask"></div>
-        <div class="dplayer-video-wrap">
-            ${this.tplVideo(true, options.video.pic, options.screenshot, options.preload, options.video.url, options.subtitle)}
-            ${options.logo ? `
-            <div class="dplayer-logo"><img src="${options.logo}"></div>
-            ` : ``}
-            <div class="dplayer-danmaku" style="${options.danmaku ? this.tplDanmakumargin(options.danmaku.margin) : ``}">
-                <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>
-                ${options.danmaku ? `<span class="dplayer-danloading">${tran('Danmaku is loading')}</span>` : ``}
-                <span class="diplayer-loading-icon">${Icons.loading}</span>
-            </div>
-        </div>
-        <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">
-                    <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>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#fff" checked>
-                            <span style="background: #fff;"></span>
-                        </label>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#e54256">
-                            <span style="background: #e54256"></span>
-                        </label>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#ffe133">
-                            <span style="background: #ffe133"></span>
-                        </label>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#64DD17">
-                            <span style="background: #64DD17"></span>
-                        </label>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#39ccff">
-                            <span style="background: #39ccff"></span>
-                        </label>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-color-${index}" value="#D500F9">
-                            <span style="background: #D500F9"></span>
-                        </label>
-                    </div>
-                    <div class="dplayer-comment-setting-type">
-                        <div class="dplayer-comment-setting-title">${tran('Set danmaku type')}</div>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-type-${index}" value="top">
-                            <span>${tran('Top')}</span>
-                        </label>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-type-${index}" value="right" checked>
-                            <span>${tran('Rolling')}</span>
-                        </label>
-                        <label>
-                            <input type="radio" name="dplayer-danmaku-type-${index}" value="bottom">
-                            <span>${tran('Bottom')}</span>
-                        </label>
-                    </div>
-                </div>
-                <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>
-            <div class="dplayer-icons dplayer-icons-left">
-                <button class="dplayer-icon dplayer-play-icon">
-                    <span class="dplayer-icon-content">${Icons.play}</span>
-                </button>
-                <div class="dplayer-volume">
-                    <button class="dplayer-icon dplayer-volume-icon">
-                        <span class="dplayer-icon-content">${Icons.volumeDown}</span>
-                    </button>
-                    <div class="dplayer-volume-bar-wrap" data-balloon-pos="up">
-                        <div class="dplayer-volume-bar">
-                            <div class="dplayer-volume-bar-inner" style="background: ${options.theme};">
-                                <span class="dplayer-thumb" style="background: ${options.theme}"></span>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <span class="dplayer-time"><span class="dplayer-ptime">0:00</span> / <span class="dplayer-dtime">0:00</span></span>
-                ${options.live ? `<span class="dplayer-live-badge"><span class="dplayer-live-dot" style="background: ${options.theme};"></span>${tran('Live')}</span>` : ''}
-            </div>
-            <div class="dplayer-icons dplayer-icons-right">
-                ${options.video.quality ? `
-                <div class="dplayer-quality">
-                    <button class="dplayer-icon dplayer-quality-icon">${options.video.quality[options.video.defaultQuality].name}</button>
-                    <div class="dplayer-quality-mask">
-                        ${this.tplQualityList(options.video.quality)}
-                    </div>
-                </div>
-                ` : ``}
-                ${options.screenshot ? `
-                <a href="#" class="dplayer-icon dplayer-camera-icon" data-balloon="${tran('Screenshot')}" data-balloon-pos="up">
-                    <span class="dplayer-icon-content">${Icons.camera}</span>
-                </a>
-                ` : ``}
-                <div class="dplayer-comment">
-                    <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>
-                ${options.subtitle ? `
-                <div class="dplayer-subtitle-btn">
-                    <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>
-                ` : ``}
-                <div class="dplayer-setting">
-                    <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>
-                                <div class="dplayer-toggle">
-                                    ${Icons.right}
-                                </div>
-                            </div>
-                            <div class="dplayer-setting-item dplayer-setting-loop">
-                                <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>
-                                <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>
-                                <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 for danmaku')}</span>
-                                <div class="dplayer-danmaku-bar-wrap">
-                                    <div class="dplayer-danmaku-bar">
-                                        <div class="dplayer-danmaku-bar-inner">
-                                            <span class="dplayer-thumb"></span>
-                                        </div>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                        <div class="dplayer-setting-speed-panel">
-                            <div class="dplayer-setting-speed-item" data-speed="0.5">
-                                <span class="dplayer-label">0.5</span>
-                            </div>
-                            <div class="dplayer-setting-speed-item" data-speed="0.75">
-                                <span class="dplayer-label">0.75</span>
-                            </div>
-                            <div class="dplayer-setting-speed-item" data-speed="1">
-                                <span class="dplayer-label">${tran('Normal')}</span>
-                            </div>
-                            <div class="dplayer-setting-speed-item" data-speed="1.25">
-                                <span class="dplayer-label">1.25</span>
-                            </div>
-                            <div class="dplayer-setting-speed-item" data-speed="1.5">
-                                <span class="dplayer-label">1.5</span>
-                            </div>
-                            <div class="dplayer-setting-speed-item" data-speed="2">
-                                <span class="dplayer-label">2</span>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                <div class="dplayer-full">
-                    <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('Full screen')}" data-balloon-pos="up">
-                        <span class="dplayer-icon-content">${Icons.full}</span>
-                    </button>
-                </div>
-            </div>
-            <div class="dplayer-bar-wrap">
-                <div class="dplayer-bar-time hidden">00:00</div>
-                <div class="dplayer-bar-preview"></div>
-                <div class="dplayer-bar">
-                    <div class="dplayer-loaded" style="width: 0;"></div>
-                    <div class="dplayer-played" style="width: 0; background: ${options.theme}">
-                        <span class="dplayer-thumb" style="background: ${options.theme}"></span>
-                    </div>
-                </div>
-            </div>
-        </div>
-        <div class="dplayer-info-panel dplayer-info-panel-hide">
-            <div class="dplayer-info-panel-close">[x]</div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-version">
-                <span class="dplayer-info-panel-item-title">Player version</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-fps">
-                <span class="dplayer-info-panel-item-title">Player FPS</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-type">
-                <span class="dplayer-info-panel-item-title">Video type</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-url">
-                <span class="dplayer-info-panel-item-title">Video url</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-resolution">
-                <span class="dplayer-info-panel-item-title">Video resolution</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-duration">
-                <span class="dplayer-info-panel-item-title">Video duration</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            ${options.danmaku ? `
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-danmaku-id">
-                <span class="dplayer-info-panel-item-title">Danamku id</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-danmaku-api">
-                <span class="dplayer-info-panel-item-title">Danamku api</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>
-            <div class="dplayer-info-panel-item dplayer-info-panel-item-danmaku-amount">
-                <span class="dplayer-info-panel-item-title">Danamku amount</span>
-                <span class="dplayer-info-panel-item-data"></span>
-            </div>` : ''}
-        </div>
-        ${this.tplContextmenuList(options.contextmenu, tran)}
-        <div class="dplayer-notice"></div>`;
-    }
-
-    tplDanmakumargin (margin) {
-        let result = '';
-        if (margin) {
-            for (const key in margin) {
-                result += `${key}:${margin[key]};`;
-            }
-        }
-        return result;
-    }
-
-    tplContextmenuList (contextmenu, tran) {
-        let result = '<div class="dplayer-menu">';
-        for (let i = 0; i < contextmenu.length; i++) {
-            result += `<div class="dplayer-menu-item"><a target="_blank" href="${contextmenu[i].link || 'javascript:void(0);'}">${tran(contextmenu[i].text)}</a></div>`;
-        }
-        result += '</div>';
-
-        return result;
-    }
-
-    tplQualityList (quality) {
-        let result = '<div class="dplayer-quality-list">';
-        for (let i = 0; i < quality.length; i++) {
-            result += `<div class="dplayer-quality-item" data-index="${i}">${quality[i].name}</div>`;
-        }
-        result += '</div>';
-
-        return result;
-    }
-
-    tplVideo (current, pic, screenshot, preload, url, subtitle) {
-        const enableSubtitle = subtitle && subtitle.type === 'webvtt';
-        return `
-        <video class="dplayer-video ${current ? `dplayer-video-current"` : ``}" ${pic ? `poster="${pic}"` : ``} webkit-playsinline playsinline ${screenshot || enableSubtitle ? `crossorigin="anonymous"` : ``} ${preload ? `preload="${preload}"` : ``} src="${url}">
-            ${enableSubtitle ? `<track kind="metadata" default src="${subtitle.url}"></track>` : ``}
-        </video>`;
-    }
 }
 
 export default Template;

+ 262 - 0
src/template/player.art

@@ -0,0 +1,262 @@
+<div class="dplayer-mask"></div>
+<div class="dplayer-video-wrap">
+    {{ include './video.art' video }}
+    {{ if options.logo }}
+    <div class="dplayer-logo">
+        <img src="{{ options.logo }}">
+    </div>
+    {{ /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 is loading') }}</span>
+        {{ /if }}
+        <span class="diplayer-loading-icon">{{@ icons.loading }}</span>
+    </div>
+</div>
+<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">
+            <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>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#fff" checked>
+                    <span style="background: #fff;"></span>
+                </label>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#e54256">
+                    <span style="background: #e54256"></span>
+                </label>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#ffe133">
+                    <span style="background: #ffe133"></span>
+                </label>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#64DD17">
+                    <span style="background: #64DD17"></span>
+                </label>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#39ccff">
+                    <span style="background: #39ccff"></span>
+                </label>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-color-{{ index }}" value="#D500F9">
+                    <span style="background: #D500F9"></span>
+                </label>
+            </div>
+            <div class="dplayer-comment-setting-type">
+                <div class="dplayer-comment-setting-title">{{ tran('Set danmaku type') }}</div>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-type-{{ index }}" value="top">
+                    <span>{{ tran('Top') }}</span>
+                </label>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-type-{{ index }}" value="right" checked>
+                    <span>{{ tran('Rolling') }}</span>
+                </label>
+                <label>
+                    <input type="radio" name="dplayer-danmaku-type-{{ index }}" value="bottom">
+                    <span>{{ tran('Bottom') }}</span>
+                </label>
+            </div>
+        </div>
+        <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>
+    <div class="dplayer-icons dplayer-icons-left">
+        <button class="dplayer-icon dplayer-play-icon">
+            <span class="dplayer-icon-content">{{@ icons.play }}</span>
+        </button>
+        <div class="dplayer-volume">
+            <button class="dplayer-icon dplayer-volume-icon">
+                <span class="dplayer-icon-content">{{@ icons.volumeDown }}</span>
+            </button>
+            <div class="dplayer-volume-bar-wrap" data-balloon-pos="up">
+                <div class="dplayer-volume-bar">
+                    <div class="dplayer-volume-bar-inner" style="background: {{ options.theme }};">
+                        <span class="dplayer-thumb" style="background: {{ options.theme }}"></span>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <span class="dplayer-time">
+            <span class="dplayer-ptime">0:00</span> /
+            <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>
+        {{ /if }}
+    </div>
+    <div class="dplayer-icons dplayer-icons-right">
+        {{ if options.video.quality }}
+        <div class="dplayer-quality">
+            <button class="dplayer-icon dplayer-quality-icon">{{ options.video.quality[options.video.defaultQuality].name }}</button>
+            <div class="dplayer-quality-mask">
+                <div class="dplayer-quality-list"></div>
+                {{ each options.video.quality }}
+                    <div class="dplayer-quality-item" data-index="{{ $index }}">{{ $value.name }}</div>
+                {{ /each }}
+                </div>
+            </div>
+        </div>
+        {{ /if }}
+        {{ if options.screenshot }}
+        <a href="#" class="dplayer-icon dplayer-camera-icon" data-balloon="{{ tran('Screenshot') }}" data-balloon-pos="up">
+            <span class="dplayer-icon-content">{{@ icons.camera }}</span>
+        </a>
+        {{ /if }}
+        <div class="dplayer-comment">
+            <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 }}
+        <div class="dplayer-subtitle-btn">
+            <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>
+        {{ /if }}
+        <div class="dplayer-setting">
+            <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>
+                        <div class="dplayer-toggle">{{@ icons.right }}</div>
+                    </div>
+                    <div class="dplayer-setting-item dplayer-setting-loop">
+                        <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>
+                        <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>
+                        <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 for danmaku') }}</span>
+                        <div class="dplayer-danmaku-bar-wrap">
+                            <div class="dplayer-danmaku-bar">
+                                <div class="dplayer-danmaku-bar-inner">
+                                    <span class="dplayer-thumb"></span>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="dplayer-setting-speed-panel">
+                    <div class="dplayer-setting-speed-item" data-speed="0.5">
+                        <span class="dplayer-label">0.5</span>
+                    </div>
+                    <div class="dplayer-setting-speed-item" data-speed="0.75">
+                        <span class="dplayer-label">0.75</span>
+                    </div>
+                    <div class="dplayer-setting-speed-item" data-speed="1">
+                        <span class="dplayer-label">{{ tran('Normal') }}</span>
+                    </div>
+                    <div class="dplayer-setting-speed-item" data-speed="1.25">
+                        <span class="dplayer-label">1.25</span>
+                    </div>
+                    <div class="dplayer-setting-speed-item" data-speed="1.5">
+                        <span class="dplayer-label">1.5</span>
+                    </div>
+                    <div class="dplayer-setting-speed-item" data-speed="2">
+                        <span class="dplayer-label">2</span>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="dplayer-full">
+            <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('Full screen') }}" data-balloon-pos="up">
+                <span class="dplayer-icon-content">{{@ icons.full }}</span>
+            </button>
+        </div>
+    </div>
+    <div class="dplayer-bar-wrap">
+        <div class="dplayer-bar-time hidden">00:00</div>
+        <div class="dplayer-bar-preview"></div>
+        <div class="dplayer-bar">
+            <div class="dplayer-loaded" style="width: 0;"></div>
+            <div class="dplayer-played" style="width: 0; background: {{ options.theme }}">
+                <span class="dplayer-thumb" style="background: {{ options.theme }}"></span>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="dplayer-info-panel dplayer-info-panel-hide">
+    <div class="dplayer-info-panel-close">[x]</div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-version">
+        <span class="dplayer-info-panel-item-title">Player version</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-fps">
+        <span class="dplayer-info-panel-item-title">Player FPS</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-type">
+        <span class="dplayer-info-panel-item-title">Video type</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-url">
+        <span class="dplayer-info-panel-item-title">Video url</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-resolution">
+        <span class="dplayer-info-panel-item-title">Video resolution</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-duration">
+        <span class="dplayer-info-panel-item-title">Video duration</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    {{ if options.danmaku }}
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-danmaku-id">
+        <span class="dplayer-info-panel-item-title">Danamku id</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-danmaku-api">
+        <span class="dplayer-info-panel-item-title">Danamku api</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    <div class="dplayer-info-panel-item dplayer-info-panel-item-danmaku-amount">
+        <span class="dplayer-info-panel-item-title">Danamku amount</span>
+        <span class="dplayer-info-panel-item-data"></span>
+    </div>
+    {{ /if }}
+</div>
+<div class="dplayer-menu">
+    {{ each options.contextmenu }}
+        <div class="dplayer-menu-item">
+            <a target="_blank" href="{{ $value.link || 'javascript:void(0);' }}">{{ tran($value.text) }}</a>
+        </div>
+    {{ /each }}
+</div>
+<div class="dplayer-notice"></div>

+ 14 - 0
src/template/video.art

@@ -0,0 +1,14 @@
+{{ set enableSubtitle = subtitle && subtitle.type === 'webvtt' }}
+<video
+    class="dplayer-video {{ if current }}dplayer-video-current{{ /if }}"
+    webkit-playsinline
+    playsinline
+    {{ if pic }}poster="{{ pic }}"{{ /if }}
+    {{ if screenshot || enableSubtitle }}crossorigin="anonymous"{{ /if }}
+    {{ if preload }}preload="{{ preload }}"{{ /if }}
+    {{ if url }}src="{{ url }}"{{ /if }}
+    >
+    {{ if enableSubtitle }}
+    <track kind="metadata" default src="{{ subtitle.url }}"></track>
+    {{ /if }}
+</video>

+ 4 - 0
webpack/dev.config.js

@@ -79,6 +79,10 @@ module.exports = {
             {
                 test: /\.svg$/,
                 loader: 'svg-inline-loader'
+            },
+            {
+                test: /\.art$/,
+                loader: 'art-template-loader'
             }
         ]
     },

+ 4 - 0
webpack/prod.config.js

@@ -87,6 +87,10 @@ module.exports = {
             {
                 test: /\.svg$/,
                 loader: 'svg-inline-loader'
+            },
+            {
+                test: /\.art$/,
+                loader: 'art-template-loader'
             }
         ]
     },

+ 107 - 2
yarn.lock

@@ -189,6 +189,26 @@ arrify@^1.0.0:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/arrify/download/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
 
+art-template-loader@1.4.3:
+  version "1.4.3"
+  resolved "https://registry.npmjs.org/art-template-loader/-/art-template-loader-1.4.3.tgz#0c22565fe2f6cee37ff7dedfffbf8b53e0fba02e"
+  dependencies:
+    loader-utils "^1.1.0"
+
+art-template@4.12.2:
+  version "4.12.2"
+  resolved "http://registry.npm.bilibili.co/art-template/download/art-template-4.12.2.tgz#a41eb82d9679bbd1c73f1f838ff46e8eb0612565"
+  dependencies:
+    acorn "^5.0.3"
+    detect-node "^2.0.3"
+    escodegen "^1.8.1"
+    estraverse "^4.2.0"
+    html-minifier "^3.4.3"
+    is-keyword-js "^1.0.3"
+    js-tokens "^3.0.1"
+    merge-source-map "^1.0.3"
+    source-map "^0.5.6"
+
 asn1.js@^4.0.0:
   version "4.9.2"
   resolved "http://registry.npm.taobao.org/asn1.js/download/asn1.js-4.9.2.tgz#8117ef4f7ed87cd8f89044b5bff97ac243a16c9a"
@@ -1005,6 +1025,13 @@ callsites@^0.2.0:
   version "0.2.0"
   resolved "http://registry.npm.taobao.org/callsites/download/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
 
+camel-case@3.0.x:
+  version "3.0.0"
+  resolved "http://registry.npm.bilibili.co/camel-case/download/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.1"
+
 camelcase-keys@^2.0.0:
   version "2.1.0"
   resolved "http://registry.npm.taobao.org/camelcase-keys/download/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
@@ -1144,6 +1171,12 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
+clean-css@4.1.x:
+  version "4.1.9"
+  resolved "http://registry.npm.bilibili.co/clean-css/download/clean-css-4.1.9.tgz#35cee8ae7687a49b98034f70de00c4edd3826301"
+  dependencies:
+    source-map "0.5.x"
+
 cli-cursor@^2.1.0:
   version "2.1.0"
   resolved "http://registry.npm.taobao.org/cli-cursor/download/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
@@ -1246,10 +1279,14 @@ combined-stream@^1.0.5, combined-stream@~1.0.5:
   dependencies:
     delayed-stream "~1.0.0"
 
-commander@^2.9.0:
+commander@2.12.x, commander@^2.9.0:
   version "2.12.2"
   resolved "http://registry.npm.taobao.org/commander/download/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555"
 
+commander@~2.13.0:
+  version "2.13.0"
+  resolved "http://registry.npm.bilibili.co/commander/download/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
+
 commondir@^1.0.1:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@@ -2585,6 +2622,10 @@ hawk@~6.0.2:
     hoek "4.x.x"
     sntp "2.x.x"
 
+he@1.1.x:
+  version "1.1.1"
+  resolved "http://registry.npm.bilibili.co/he/download/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
+
 hmac-drbg@^1.0.0:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/hmac-drbg/download/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -2629,6 +2670,19 @@ html-entities@^1.2.0:
   version "1.2.1"
   resolved "http://registry.npm.taobao.org/html-entities/download/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
 
+html-minifier@^3.4.3:
+  version "3.5.8"
+  resolved "http://registry.npm.bilibili.co/html-minifier/download/html-minifier-3.5.8.tgz#5ccdb1f73a0d654e6090147511f6e6b2ee312700"
+  dependencies:
+    camel-case "3.0.x"
+    clean-css "4.1.x"
+    commander "2.12.x"
+    he "1.1.x"
+    ncname "1.0.x"
+    param-case "2.1.x"
+    relateurl "0.2.x"
+    uglify-js "3.3.x"
+
 http-deceiver@^1.2.7:
   version "1.2.7"
   resolved "http://registry.npm.taobao.org/http-deceiver/download/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
@@ -2937,6 +2991,10 @@ is-glob@^4.0.0:
   dependencies:
     is-extglob "^2.1.1"
 
+is-keyword-js@^1.0.3:
+  version "1.0.3"
+  resolved "http://registry.npm.bilibili.co/is-keyword-js/download/is-keyword-js-1.0.3.tgz#ac30dcf35b671f4b27b17f5cb57235126021132d"
+
 is-my-json-valid@^2.12.4:
   version "2.16.1"
   resolved "http://registry.npm.taobao.org/is-my-json-valid/download/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11"
@@ -3074,7 +3132,7 @@ js-base64@^2.1.8, js-base64@^2.1.9:
   version "2.4.0"
   resolved "http://registry.npm.taobao.org/js-base64/download/js-base64-2.4.0.tgz#9e566fee624751a1d720c966cd6226d29d4025aa"
 
-js-tokens@^3.0.0, js-tokens@^3.0.2:
+js-tokens@^3.0.0, js-tokens@^3.0.1, js-tokens@^3.0.2:
   version "3.0.2"
   resolved "http://registry.npm.taobao.org/js-tokens/download/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
 
@@ -3319,6 +3377,10 @@ loud-rejection@^1.0.0:
     currently-unhandled "^0.4.1"
     signal-exit "^3.0.0"
 
+lower-case@^1.1.1:
+  version "1.1.4"
+  resolved "http://registry.npm.bilibili.co/lower-case/download/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+
 lru-cache@^4.0.1:
   version "4.1.1"
   resolved "http://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
@@ -3397,6 +3459,12 @@ merge-descriptors@1.0.1:
   version "1.0.1"
   resolved "http://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
 
+merge-source-map@^1.0.3:
+  version "1.1.0"
+  resolved "http://registry.npm.bilibili.co/merge-source-map/download/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646"
+  dependencies:
+    source-map "^0.6.1"
+
 methods@~1.1.2:
   version "1.1.2"
   resolved "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
@@ -3555,10 +3623,22 @@ natural-compare@^1.4.0:
   version "1.4.0"
   resolved "http://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
 
+ncname@1.0.x:
+  version "1.0.0"
+  resolved "http://registry.npm.bilibili.co/ncname/download/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c"
+  dependencies:
+    xml-char-classes "^1.0.0"
+
 negotiator@0.6.1:
   version "0.6.1"
   resolved "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
 
+no-case@^2.2.0:
+  version "2.3.2"
+  resolved "http://registry.npm.bilibili.co/no-case/download/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+  dependencies:
+    lower-case "^1.1.1"
+
 node-forge@0.6.33:
   version "0.6.33"
   resolved "http://registry.npm.taobao.org/node-forge/download/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc"
@@ -3860,6 +3940,12 @@ pako@~1.0.5:
   version "1.0.6"
   resolved "http://registry.npm.taobao.org/pako/download/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
 
+param-case@2.1.x:
+  version "2.1.1"
+  resolved "http://registry.npm.bilibili.co/param-case/download/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+  dependencies:
+    no-case "^2.2.0"
+
 parse-asn1@^5.0.0:
   version "5.1.0"
   resolved "http://registry.npm.taobao.org/parse-asn1/download/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
@@ -4563,6 +4649,10 @@ regjsparser@^0.1.4:
   dependencies:
     jsesc "~0.5.0"
 
+relateurl@0.2.x:
+  version "0.2.7"
+  resolved "http://registry.npm.bilibili.co/relateurl/download/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+
 remove-trailing-separator@^1.0.1:
   version "1.1.0"
   resolved "http://registry.npm.taobao.org/remove-trailing-separator/download/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
@@ -5414,6 +5504,13 @@ typedarray@^0.0.6:
   version "0.0.6"
   resolved "http://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
 
+uglify-js@3.3.x:
+  version "3.3.9"
+  resolved "http://registry.npm.bilibili.co/uglify-js/download/uglify-js-3.3.9.tgz#33869666c8ab7f7658ce3d22f0f1ced40097d33a"
+  dependencies:
+    commander "~2.13.0"
+    source-map "~0.6.1"
+
 uglify-js@^2.8.29:
   version "2.8.29"
   resolved "http://registry.npm.taobao.org/uglify-js/download/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
@@ -5473,6 +5570,10 @@ unset-value@^1.0.0:
     has-value "^0.3.1"
     isobject "^3.0.0"
 
+upper-case@^1.1.1:
+  version "1.1.3"
+  resolved "http://registry.npm.bilibili.co/upper-case/download/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+
 urix@^0.1.0:
   version "0.1.0"
   resolved "http://registry.npm.taobao.org/urix/download/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
@@ -5719,6 +5820,10 @@ write@^0.2.1:
   dependencies:
     mkdirp "^0.5.1"
 
+xml-char-classes@^1.0.0:
+  version "1.0.0"
+  resolved "http://registry.npm.bilibili.co/xml-char-classes/download/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d"
+
 xtend@^4.0.0:
   version "4.0.1"
   resolved "http://registry.npm.taobao.org/xtend/download/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"