Browse Source

Add AirPlay Support on iOS / Mac Safari

Aladdin 5 years ago
parent
commit
583b1c9771

+ 6 - 5
demo/demo.js

@@ -2,7 +2,7 @@
 const stats = new Stats();
 stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
 document.body.appendChild(stats.dom);
-function animate () {
+function animate() {
     stats.begin();
     // monitored code goes here
     stats.end();
@@ -14,7 +14,7 @@ requestAnimationFrame(animate);
 initPlayers();
 handleEvent();
 
-function handleEvent () {
+function handleEvent() {
     document.getElementById('dplayer-dialog').addEventListener('click', (e) => {
         const $clickDom = e.currentTarget;
         const isShowStatus = $clickDom.getAttribute('data-show');
@@ -35,7 +35,7 @@ function handleEvent () {
     });
 }
 
-function initPlayers () {
+function initPlayers() {
     // dplayer-float
     window.dpFloat = new DPlayer({
         container: document.getElementById('dplayer-container'),
@@ -82,6 +82,7 @@ function initPlayers () {
         theme: '#FADFA3',
         loop: true,
         screenshot: true,
+        airplay: true,
         hotkey: true,
         logo: 'https://i.loli.net/2019/06/06/5cf8c5d94521136430.png',
         volume: 0.2,
@@ -235,14 +236,14 @@ function initPlayers () {
     // });
 }
 
-function clearPlayers () {
+function clearPlayers() {
     for (let i = 0; i < 6; i++) {
         window['dp' + (i + 1)].pause();
         document.getElementById('dplayer' + (i + 1)).innerHTML = '';
     }
 }
 
-function switchDPlayer () {
+function switchDPlayer() {
     if (dp2.option.danmaku.id !== '5rGf5Y2X55qu6Z2p') {
         dp2.switchVideo({
             url: 'http://static.smartisanos.cn/common/video/t1-ui.mp4',

+ 1 - 0
src/assets/airplay.svg

@@ -0,0 +1 @@
+<?xml version="1.0" ?><svg viewBox="0 0 288 288" xmlns="http://www.w3.org/2000/svg"><path d="M288 90v96c0 20-16 36-36 36h-10c-16 0-16-24 0-24h10c7 0 12-5 12-12V90c0-7-5-12-12-12H36c-7 0-12 5-12 12v96c0 7 5 12 12 12h10c16 0 16 24 0 24H36c-20 0-36-16-36-36V90c0-20 16-36 36-36h216c20 0 36 16 36 36zm-120 62l48 68c14 20 1 38-20 38H92c-21 0-34-18-20-38l48-68c13-18 35-18 48 0z"/></svg>

+ 3 - 3
src/css/player.scss

@@ -11,7 +11,7 @@
     svg {
         width: 100%;
         height: 100%;
-        
+
         path,
         circle {
             fill: #fff;
@@ -89,7 +89,7 @@
 
     &.dplayer-arrow {
         .dplayer-danmaku {
-            font-size: 18px
+            font-size: 18px;
         }
         .dplayer-icon {
             margin: 0 -3px;
@@ -97,7 +97,6 @@
     }
 
     &.dplayer-playing {
-
         .dplayer-danmaku .dplayer-danmaku-move {
             animation-play-state: running;
         }
@@ -167,6 +166,7 @@
         .dplayer-controller .dplayer-icons {
             .dplayer-volume,
             .dplayer-camera-icon,
+            .dplayer-airplay-icon,
             .dplayer-play-icon {
                 display: none;
             }

+ 32 - 0
src/js/controller.js

@@ -30,6 +30,9 @@ class Controller {
         this.initScreenshotButton();
         this.initSubtitleButton();
         this.initHighlights();
+        if (utils.isSafari) {
+            this.initAirplayButton();
+        }
         if (!utils.isMobile) {
             this.initVolumeButton();
         }
@@ -249,6 +252,35 @@ class Controller {
         }
     }
 
+    initAirplayButton() {
+        if (this.player.options.airplay) {
+            if (window.WebKitPlaybackTargetAvailabilityEvent) {
+                this.player.video.addEventListener(
+                    'webkitplaybacktargetavailabilitychanged',
+                    function (event) {
+                        switch (event.availability) {
+                            case 'available':
+                                this.template.airplayButton.disable = false;
+                                break;
+
+                            default:
+                                this.template.airplayButton.disable = true;
+                        }
+
+                        this.template.airplayButton.addEventListener(
+                            'click',
+                            function () {
+                                this.video.webkitShowPlaybackTargetPicker();
+                            }.bind(this)
+                        );
+                    }.bind(this.player)
+                );
+            } else {
+                this.player.template.airplayButton.style.display = 'none';
+            }
+        }
+    }
+
     initSubtitleButton() {
         if (this.player.options.subtitle) {
             this.player.events.on('subtitle_show', () => {

+ 2 - 0
src/js/i18n.js

@@ -52,6 +52,7 @@ const tranTxt = {
         'Web full screen': '页面全屏',
         Send: '发送',
         Screenshot: '截图',
+        AirPlay: '无线投屏',
         s: '秒',
         'Show subtitle': '显示字幕',
         'Hide subtitle': '隐藏字幕',
@@ -91,6 +92,7 @@ const tranTxt = {
         'Web full screen': '頁面全螢幕',
         Send: '發送',
         Screenshot: '截圖',
+        AirPlay: '無線投屏',
         s: '秒',
         'Show subtitle': '顯示字幕',
         'Hide subtitle': '隱藏字幕',

+ 2 - 0
src/js/icons.js

@@ -12,6 +12,7 @@ import commentOff from '../assets/comment-off.svg';
 import send from '../assets/send.svg';
 import pallette from '../assets/pallette.svg';
 import camera from '../assets/camera.svg';
+import airplay from '../assets/airplay.svg';
 import subtitle from '../assets/subtitle.svg';
 import loading from '../assets/loading.svg';
 
@@ -32,6 +33,7 @@ const Icons = {
     camera: camera,
     subtitle: subtitle,
     loading: loading,
+    airplay: airplay,
 };
 
 export default Icons;

+ 1 - 0
src/js/options.js

@@ -11,6 +11,7 @@ export default (options) => {
         loop: false,
         lang: (navigator.language || navigator.browserLanguage).toLowerCase(),
         screenshot: false,
+        airplay: false,
         hotkey: true,
         preload: 'metadata',
         volume: 0.7,

+ 2 - 0
src/js/template.js

@@ -22,6 +22,7 @@ class Template {
                 current: true,
                 pic: this.options.video.pic,
                 screenshot: this.options.screenshot,
+                airplay: this.options.airplay,
                 preload: this.options.preload,
                 url: this.options.video.url,
                 subtitle: this.options.subtitle,
@@ -78,6 +79,7 @@ class Template {
         this.menuItem = this.container.querySelectorAll('.dplayer-menu-item');
         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.subtitleButton = this.container.querySelector('.dplayer-subtitle-icon');
         this.subtitleButtonInner = this.container.querySelector('.dplayer-subtitle-icon .dplayer-icon-content');
         this.subtitle = this.container.querySelector('.dplayer-subtitle');

+ 4 - 0
src/js/utils.js

@@ -1,5 +1,7 @@
 const isMobile = /mobile/i.test(window.navigator.userAgent);
 
+const isSafari = /Safari/i.test(window.navigator.userAgent);
+
 const utils = {
     /**
      * Parse second to time string
@@ -89,6 +91,8 @@ const utils = {
 
     isMobile: isMobile,
 
+    isSafari: isSafari,
+
     isFirefox: /firefox/i.test(window.navigator.userAgent),
 
     isChrome: /chrome/i.test(window.navigator.userAgent),

+ 5 - 0
src/template/player.art

@@ -115,6 +115,11 @@
             <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">
+            <span class="dplayer-icon-content">{{@ icons.airplay }}</span>
+        </div>
+        {{ /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>

+ 1 - 0
src/template/video.art

@@ -2,6 +2,7 @@
 <video
     class="dplayer-video {{ if current }}dplayer-video-current{{ /if }}"
     webkit-playsinline
+    {{ if airplay }} x-webkit-airplay="allow" {{ /if }}
     playsinline
     {{ if pic }}poster="{{ pic }}"{{ /if }}
     {{ if screenshot || enableSubtitle }}crossorigin="anonymous"{{ /if }}