mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-28 10:31:20 -08:00
Merge branch 'master' of https://github.com/zhw2590582/ArtPlayer
This commit is contained in:
commit
c7299b926e
62 files changed
+10765
-705
No files matched your search
@@ -495,6 +495,7 @@ export default class Danmuku {
|
||||
|
||||
// 获取准备好发送的弹幕,可能包含ready和wait状态的弹幕
|
||||
const readys = this.readys;
|
||||
|
||||
for (let index = 0; index < readys.length; index++) {
|
||||
const danmu = readys[index];
|
||||
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
{
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"name": "artplayer-plugin-vast",
|
||||
"types": "types/artplayer-plugin-vast.d.ts",
|
||||
"description": "vast plugin for ArtPlayer",
|
||||
"main": "dist/artplayer-plugin-vast.js",
|
||||
"legacy": "dist/artplayer-plugin-vast.legacy.js",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
]
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"name": "artplayer-plugin-vast",
|
||||
"types": "types/artplayer-plugin-vast.d.ts",
|
||||
"description": "vast plugin for ArtPlayer",
|
||||
"main": "dist/artplayer-plugin-vast.js",
|
||||
"legacy": "dist/artplayer-plugin-vast.legacy.js",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"dependencies": {
|
||||
"@glomex/vast-ima-player": "^1.21.0"
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,55 @@
|
||||
import style from 'bundle-text:./style.less';
|
||||
import { Player, PlayerOptions, loadImaSdk } from '@glomex/vast-ima-player';
|
||||
|
||||
export default function artplayerPluginVast(callback) {
|
||||
return async (art) => {
|
||||
const { template, constructor } = art;
|
||||
const { createElement, setStyles, append } = constructor.utils;
|
||||
const { $video, $player } = template;
|
||||
|
||||
await loadImaSdk();
|
||||
const google = window.google;
|
||||
const ima = google.ima;
|
||||
|
||||
const adsRenderingSettings = new ima.AdsRenderingSettings();
|
||||
const playerOptions = new PlayerOptions();
|
||||
|
||||
const id = `art-${Date.now()}`;
|
||||
const $container = createElement('div');
|
||||
append($player, $container);
|
||||
$container.id = id;
|
||||
setStyles($container, {
|
||||
position: 'absolute',
|
||||
inset: '0',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: '150',
|
||||
display: 'none',
|
||||
});
|
||||
|
||||
const imaPlayer = new Player(ima, $video, $container, adsRenderingSettings, playerOptions);
|
||||
|
||||
function playUrl(url) {
|
||||
const playAdsRequest = new ima.AdsRequest();
|
||||
playAdsRequest.adTagUrl = url;
|
||||
imaPlayer.playAds(playAdsRequest);
|
||||
}
|
||||
|
||||
function playRes(res) {
|
||||
const playAdsRequest = new ima.AdsRequest();
|
||||
playAdsRequest.adsResponse = res;
|
||||
imaPlayer.playAds(playAdsRequest);
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
await callback({ art, id, ima, imaPlayer, $container, playUrl, playRes });
|
||||
}
|
||||
|
||||
export default function artplayerPluginVast(option) {
|
||||
return (art) => {
|
||||
return {
|
||||
name: 'artplayerPluginVast',
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
const id = 'artplayer-plugin-vast';
|
||||
const $style = document.getElementById(id);
|
||||
if ($style) {
|
||||
$style.textContent = style;
|
||||
} else {
|
||||
const $style = document.createElement('style');
|
||||
$style.id = id;
|
||||
$style.textContent = style;
|
||||
document.head.appendChild($style);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayerPluginVast'] = artplayerPluginVast;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
.artplayer-plugin-vast {
|
||||
//
|
||||
}
|
||||
@@ -3,9 +3,15 @@ import type Artplayer from 'artplayer';
|
||||
export = artplayerPluginVast;
|
||||
export as namespace artplayerPluginVast;
|
||||
|
||||
type Option = {
|
||||
//
|
||||
};
|
||||
type Option = (params: {
|
||||
art: Artplayer;
|
||||
id: string;
|
||||
ima: any;
|
||||
imaPlayer: any;
|
||||
$container: HTMLDivElement;
|
||||
playUrl: (url: string) => void;
|
||||
playRes: (res: string) => void;
|
||||
}) => void;
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerPluginVast';
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# artplayer-proxy-libmedia
|
||||
|
||||
libmedia proxy for ArtPlayer
|
||||
|
||||
## Demo
|
||||
|
||||
[https://artplayer.org](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-libmedia/index.js&example=libmedia)
|
||||
|
||||
## License
|
||||
|
||||
MIT © Harvey Zack
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"name": "artplayer-proxy-libmedia",
|
||||
"types": "types/artplayer-proxy-libmedia.d.ts",
|
||||
"description": "libmedia proxy for ArtPlayer",
|
||||
"main": "dist/artplayer-proxy-libmedia.js",
|
||||
"legacy": "dist/artplayer-proxy-libmedia.legacy.js",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
export default function artplayerProxyLibmedia(option) {
|
||||
return (art) => {
|
||||
return document.createElement('video');
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window['artplayerProxyLibmedia'] = artplayerProxyLibmedia;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
|
||||
export = artplayerProxyLibmedia;
|
||||
export as namespace artplayerProxyLibmedia;
|
||||
|
||||
type Option = {
|
||||
//
|
||||
};
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerProxyLibmedia';
|
||||
};
|
||||
|
||||
declare const artplayerProxyLibmedia: (option: Option) => (art: Artplayer) => Result;
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
/*!
|
||||
* artplayer-proxy-webav.js v1.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2024 Harvey Zack
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e,r,s,n){var a="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},o="function"==typeof a[s]&&a[s],h=o.cache||{},l="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function u(e,r){if(!h[e]){if(!t[e]){var n="function"==typeof a[s]&&a[s];if(!r&&n)return n(e,!0);if(o)return o(e,!0);if(l&&"string"==typeof e)return l(e);var d=Error("Cannot find module '"+e+"'");throw d.code="MODULE_NOT_FOUND",d}p.resolve=function(r){var s=t[e][1][r];return null!=s?s:r},p.cache={};var f=h[e]=new u.Module(e);t[e][0].call(f.exports,p,f,f.exports,this)}return h[e].exports;function p(t){var e=p.resolve(t);return!1===e?{}:u(e)}}u.isParcelRequire=!0,u.Module=function(t){this.id=t,this.bundle=u,this.exports={}},u.modules=t,u.cache=h,u.parent=o,u.register=function(e,r){t[e]=[function(t,e){e.exports=r},{}]},Object.defineProperty(u,"root",{get:function(){return a[s]}}),a[s]=u;for(var d=0;d<e.length;d++)u(e[d]);if(r){var f=u(r);"object"==typeof exports&&"undefined"!=typeof module?module.exports=f:"function"==typeof define&&define.amd&&define(function(){return f})}}({jc2x7:[function(t,e,r){var s=t("@parcel/transformer-js/src/esmodule-helpers.js");s.defineInteropFlag(r),s.export(r,"default",()=>a);var n=t("@webav/av-cliper");function a(){return t=>{let e,r;let{option:s,constructor:a}=t,{createElement:o,def:h}=a.utils,l=o("canvas"),u=l.getContext("2d"),d=null,f=null,p=null,c=null,m=0,g={playing:!1,duration:0,videoWidth:0,videoHeight:0,currentTime:0,playbackRate:1,paused:!0,ended:!1,readyState:0,buffered:0,muted:s.muted,volume:s.volume,autoplay:s.autoplay};function y(){p&&(clearInterval(p),p=null),f&&(f.stop(),f=null)}function _(){if(r){let t=g.muted?0:g.volume;r.gain.setValueAtTime(t,e.currentTime)}}async function b(){e||(r=(e=new AudioContext).createGain()).connect(e.destination);let s=1e6*g.currentTime,n=0,a=!0,o=performance.now();async function h(){if(!g.playing)return;let h=performance.now(),l=h-o;o=h,null!==c?(s=1e6*c,c=null,a=!0):s+=1e3*l*g.playbackRate,g.currentTime=s/1e6;let{state:p,video:m,audio:_}=await d.tick(Math.round(s));if(t.emit("video:timeupdate",{type:"timeupdate"}),"done"===p){y(),g.ended=!0,g.playing=!1,g.paused=!0,t.emit("video:ended",{type:"ended"});return}if(m&&"success"===p&&(u.clearRect(0,0,g.videoWidth,g.videoHeight),u.drawImage(m,0,0,g.videoWidth,g.videoHeight),m.close()),a)a=!1;else if(_?.[0]?.length){let t=e.createBuffer(2,_[0].length,48e3);t.copyToChannel(_[0],0),t.copyToChannel(_[1],1),(f=e.createBufferSource()).buffer=t,f.connect(r),f.playbackRate.setValueAtTime(g.playbackRate,e.currentTime),n=Math.max(e.currentTime,n),f.start(n),n+=t.duration/g.playbackRate}}y(),_(),g.playing=!0,g.paused=!1,p=setInterval(h,1e3/60)}async function w(t){let{video:e}=await d.tick(1e6*t);e&&(u.clearRect(0,0,l.width,l.height),u.drawImage(e,0,0,l.width,l.height),e.close())}function v(){let e=t.template?.$player;if(!e||s.autoSize)return;let r=l.videoWidth/l.videoHeight,n=e.clientWidth,a=e.clientHeight,o=0,h=0;n/a>r?o=(n-a*r)/2:h=(a-n/r)/2,Object.assign(l.style,{padding:`${h}px ${o}px`})}async function S(){if(!await (0,n.Combinator).isSupported())throw t.notice.show="WebAV is not supported",Error("WebAV is not supported");y(),Object.assign(g,{playing:!1,duration:0,videoWidth:0,videoHeight:0,currentTime:0,playbackRate:1,paused:!0,ended:!1,readyState:0,buffered:0,muted:s.muted,volume:s.volume,autoplay:s.autoplay}),d&&(d.destroy(),t.emit("video:abort",{type:"abort"}),t.emit("video:emptied",{type:"emptied"}));try{await Promise.resolve(),t.emit("video:loadstart",{type:"loadstart"});let e=await fetch(s.url);if(!e.body)throw Error("No response body");d=new n.MP4Clip(e.body)}catch(e){throw t.emit("video:error",e),e}let e=await d.ready;Object.assign(g,{readyState:4,duration:Math.round(e.duration/1e6),videoWidth:e.width,videoHeight:e.height}),l.width=g.videoWidth,l.height=g.videoHeight,await w(.1),v(),t.emit("video:loadedmetadata",{type:"loadedmetadata"}),t.emit("video:durationchange",{type:"durationchange"}),t.emit("video:loadeddata",{type:"loadeddata"}),t.emit("video:canplay",{type:"canplay"}),t.emit("video:canplaythrough",{type:"canplaythrough"})}return h(l,"textTracks",{get:()=>[]}),h(l,"duration",{get:()=>g.duration}),h(l,"videoWidth",{get:()=>g.videoWidth}),h(l,"videoHeight",{get:()=>g.videoHeight}),h(l,"volume",{get:()=>g.volume,set:e=>{g.volume=Math.max(0,Math.min(1,e)),_(),t.emit("video:volumechange",{type:"volumechange"})}}),h(l,"currentTime",{get:()=>g.currentTime,set:e=>{let r=Math.max(0,Math.min(e,g.duration)),s=performance.now();s-m>16&&(m=s,c=r,g.currentTime=r,g.playing||w(r),t.emit("video:timeupdate",{type:"timeupdate"}))}}),h(l,"autoplay",{get:()=>g.autoplay,set:t=>{g.autoplay=t,t&&g.readyState>=4&&l.play()}}),h(l,"src",{get:()=>s.url,set:t=>{s.url=t,S().then(()=>{s.autoplay&&l.play()})}}),h(l,"playbackRate",{get:()=>g.playbackRate,set:r=>{g.playbackRate=Math.max(.25,Math.min(2,r)),f&&fLine truncated
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
/*!
|
||||
* artplayer-proxy-webav.js v1.0.0
|
||||
* Github: https://github.com/zhw2590582/ArtPlayer
|
||||
* (c) 2017-2024 Harvey Zack
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
!function(t,e,r,n,s){var a="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},o="function"==typeof a[n]&&a[n],u=o.cache||{},l="undefined"!=typeof module&&"function"==typeof module.require&&module.require.bind(module);function c(e,r){if(!u[e]){if(!t[e]){var s="function"==typeof a[n]&&a[n];if(!r&&s)return s(e,!0);if(o)return o(e,!0);if(l&&"string"==typeof e)return l(e);var h=Error("Cannot find module '"+e+"'");throw h.code="MODULE_NOT_FOUND",h}d.resolve=function(r){var n=t[e][1][r];return null!=n?n:r},d.cache={};var f=u[e]=new c.Module(e);t[e][0].call(f.exports,d,f,f.exports,this)}return u[e].exports;function d(t){var e=d.resolve(t);return!1===e?{}:c(e)}}c.isParcelRequire=!0,c.Module=function(t){this.id=t,this.bundle=c,this.exports={}},c.modules=t,c.cache=u,c.parent=o,c.register=function(e,r){t[e]=[function(t,e){e.exports=r},{}]},Object.defineProperty(c,"root",{get:function(){return a[n]}}),a[n]=c;for(var h=0;h<e.length;h++)c(e[h]);if(r){var f=c(r);"object"==typeof exports&&"undefined"!=typeof module?module.exports=f:"function"==typeof define&&define.amd&&define(function(){return f})}}({c4SNP:[function(t,e,r){var n=t("@parcel/transformer-js/src/esmodule-helpers.js");n.defineInteropFlag(r),n.export(r,"default",function(){return u});var s=t("@swc/helpers/_/_async_to_generator"),a=t("@swc/helpers/_/_ts_generator"),o=t("@webav/av-cliper");function u(){return function(t){var e,r,n=t.option,u=t.constructor.utils,l=u.createElement,c=u.def,h=l("canvas"),f=h.getContext("2d"),d=null,p=null,m=null,_=null,y=0,g={playing:!1,duration:0,videoWidth:0,videoHeight:0,currentTime:0,playbackRate:1,paused:!0,ended:!1,readyState:0,buffered:0,muted:n.muted,volume:n.volume,autoplay:n.autoplay};function v(){m&&(clearInterval(m),m=null),p&&(p.stop(),p=null)}function b(){if(r){var t=g.muted?0:g.volume;r.gain.setValueAtTime(t,e.currentTime)}}function w(){return(w=(0,s._)(function(){var n,o,u,l;function c(){return h.apply(this,arguments)}function h(){return(h=(0,s._)(function(){var s,c,h,m,y,b,w,S;return(0,a._)(this,function(a){switch(a.label){case 0:if(!g.playing)return[2];return h=(c=performance.now())-l,l=c,null!==_?(n=1e6*_,_=null,u=!0):n+=1e3*h*g.playbackRate,g.currentTime=n/1e6,[4,d.tick(Math.round(n))];case 1:if(y=(m=a.sent()).state,b=m.video,w=m.audio,t.emit("video:timeupdate",{type:"timeupdate"}),"done"===y)return v(),g.ended=!0,g.playing=!1,g.paused=!0,t.emit("video:ended",{type:"ended"}),[2];return b&&"success"===y&&(f.clearRect(0,0,g.videoWidth,g.videoHeight),f.drawImage(b,0,0,g.videoWidth,g.videoHeight),b.close()),u?u=!1:(null==w?void 0:null===(s=w[0])||void 0===s?void 0:s.length)&&((S=e.createBuffer(2,w[0].length,48e3)).copyToChannel(w[0],0),S.copyToChannel(w[1],1),(p=e.createBufferSource()).buffer=S,p.connect(r),p.playbackRate.setValueAtTime(g.playbackRate,e.currentTime),o=Math.max(e.currentTime,o),p.start(o),o+=S.duration/g.playbackRate),[2]}})})).apply(this,arguments)}return(0,a._)(this,function(t){return e||(r=(e=new AudioContext).createGain()).connect(e.destination),n=1e6*g.currentTime,o=0,u=!0,l=performance.now(),v(),b(),g.playing=!0,g.paused=!1,m=setInterval(c,1e3/60),[2]})})).apply(this,arguments)}function S(t){return x.apply(this,arguments)}function x(){return(x=(0,s._)(function(t){var e;return(0,a._)(this,function(r){switch(r.label){case 0:return[4,d.tick(1e6*t)];case 1:return(e=r.sent().video)&&(f.clearRect(0,0,h.width,h.height),f.drawImage(e,0,0,h.width,h.height),e.close()),[2]}})})).apply(this,arguments)}function E(){var e,r=null===(e=t.template)||void 0===e?void 0:e.$player;if(r&&!n.autoSize){var s=h.videoWidth/h.videoHeight,a=r.clientWidth,o=r.clientHeight,u=0,l=0;a/o>s?u=(a-o*s)/2:l=(o-a/s)/2,Object.assign(h.style,{padding:"".concat(l,"px ").concat(u,"px")})}}function U(){return(U=(0,s._)(function(){var e,r,s;return(0,a._)(this,function(a){switch(a.label){case 0:return[4,(0,o.Combinator).isSupported()];case 1:if(!a.sent())throw t.notice.show="WebAV is not supported",Error("WebAV is not supported");v(),Object.assign(g,{playing:!1,duration:0,videoWidth:0,videoHeight:0,currentTime:0,playbackRate:1,paused:!0,ended:!1,readyState:0,buffered:0,muted:n.muted,volume:n.volume,autoplay:n.autoplay}),d&&(d.destroy(),t.emit("video:abort",{type:"abort"}),t.emit("video:emptied",{type:"emptied"})),a.label=2;case 2:return a.trys.push([2,5,,6]),[4,Promise.resolve()];case 3:return a.sent(),t.emit("video:loadstart",{type:"loadstart"}),[4,fetch(n.url)];case 4:if(!(e=a.sent()).body)throw Error("No response body");return d=new o.MP4Clip(e.body),[3,6];case 5:throw r=a.sent(),t.emit("video:error",r),r;case 6:return[4,d.ready];case 7:return Object.assign(g,{readyState:4,duration:Math.round((s=a.sent()).duration/1e6),videoWidth:s.width,videoHeight:s.height}),h.width=g.videoWidth,h.height=g.videoHeight,[4,S(.1)];case 8:return a.sent(),E(),t.emit("video:loadedmetadata",{type:"loadedmetadata"}),t.emit("video:durationchange",{type:"durationchange"})Line truncated
|
||||
@@ -1,24 +1,27 @@
|
||||
{
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"name": "artplayer-proxy-webav",
|
||||
"types": "types/artplayer-proxy-webav.d.ts",
|
||||
"description": "webav proxy for ArtPlayer",
|
||||
"main": "dist/artplayer-proxy-webav.js",
|
||||
"legacy": "dist/artplayer-proxy-webav.legacy.js",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
]
|
||||
}
|
||||
"license": "MIT",
|
||||
"version": "1.0.0",
|
||||
"name": "artplayer-proxy-webav",
|
||||
"types": "types/artplayer-proxy-webav.d.ts",
|
||||
"description": "webav proxy for ArtPlayer",
|
||||
"main": "dist/artplayer-proxy-webav.js",
|
||||
"legacy": "dist/artplayer-proxy-webav.legacy.js",
|
||||
"author": "Harvey Zack <laozhaochaguan@gmail.com>",
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"homepage": "https://artplayer.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"html5",
|
||||
"video",
|
||||
"player"
|
||||
],
|
||||
"dependencies": {
|
||||
"@webav/av-cliper": "^0.14.14"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,369 @@
|
||||
export default function artplayerProxyWebAV(option) {
|
||||
import { MP4Clip, Combinator } from '@webav/av-cliper';
|
||||
|
||||
export default function artplayerProxyWebAV(opt = {}) {
|
||||
return (art) => {
|
||||
return document.createElement('video');
|
||||
const { option, constructor } = art;
|
||||
const { createElement, def } = constructor.utils;
|
||||
|
||||
const canvas = createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
let audioCtx;
|
||||
let gainNode;
|
||||
|
||||
let clip = null;
|
||||
let audioSource = null;
|
||||
let intervalId = null;
|
||||
let seekTarget = null;
|
||||
let lastSeekTime = 0;
|
||||
|
||||
const state = {
|
||||
playing: false,
|
||||
duration: 0,
|
||||
videoWidth: 0,
|
||||
videoHeight: 0,
|
||||
currentTime: 0,
|
||||
playbackRate: 1,
|
||||
paused: true,
|
||||
ended: false,
|
||||
readyState: 0,
|
||||
buffered: 0,
|
||||
muted: option.muted,
|
||||
volume: option.volume,
|
||||
autoplay: option.autoplay,
|
||||
};
|
||||
|
||||
function reset() {
|
||||
Object.assign(state, {
|
||||
playing: false,
|
||||
duration: 0,
|
||||
videoWidth: 0,
|
||||
videoHeight: 0,
|
||||
currentTime: 0,
|
||||
playbackRate: 1,
|
||||
paused: true,
|
||||
ended: false,
|
||||
readyState: 0,
|
||||
buffered: 0,
|
||||
muted: option.muted,
|
||||
volume: option.volume,
|
||||
autoplay: option.autoplay,
|
||||
});
|
||||
}
|
||||
|
||||
function stop() {
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
intervalId = null;
|
||||
}
|
||||
if (audioSource) {
|
||||
audioSource.stop();
|
||||
audioSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
function updateVolume() {
|
||||
if (gainNode) {
|
||||
const effectiveVolume = state.muted ? 0 : state.volume;
|
||||
gainNode.gain.setValueAtTime(effectiveVolume, audioCtx.currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
async function play() {
|
||||
if (!audioCtx) {
|
||||
audioCtx = new AudioContext();
|
||||
gainNode = audioCtx.createGain();
|
||||
gainNode.connect(audioCtx.destination);
|
||||
}
|
||||
|
||||
let curTime = state.currentTime * 1e6;
|
||||
let startAt = 0;
|
||||
let first = true;
|
||||
let lastFrameTime = performance.now();
|
||||
|
||||
stop();
|
||||
updateVolume();
|
||||
|
||||
async function frameHandler() {
|
||||
if (!state.playing) return;
|
||||
|
||||
const currentFrameTime = performance.now();
|
||||
const deltaTime = currentFrameTime - lastFrameTime;
|
||||
lastFrameTime = currentFrameTime;
|
||||
|
||||
if (seekTarget !== null) {
|
||||
curTime = seekTarget * 1e6;
|
||||
seekTarget = null;
|
||||
first = true;
|
||||
} else {
|
||||
curTime += deltaTime * 1000 * state.playbackRate;
|
||||
}
|
||||
|
||||
state.currentTime = curTime / 1e6;
|
||||
|
||||
const { state: clipState, video, audio } = await clip.tick(Math.round(curTime));
|
||||
|
||||
art.emit('video:timeupdate', { type: 'timeupdate' });
|
||||
|
||||
if (clipState === 'done') {
|
||||
stop();
|
||||
state.ended = true;
|
||||
state.playing = false;
|
||||
state.paused = true;
|
||||
art.emit('video:ended', { type: 'ended' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (video && clipState === 'success') {
|
||||
ctx.clearRect(0, 0, state.videoWidth, state.videoHeight);
|
||||
ctx.drawImage(video, 0, 0, state.videoWidth, state.videoHeight);
|
||||
video.close();
|
||||
}
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else if (audio?.[0]?.length) {
|
||||
const buf = audioCtx.createBuffer(2, audio[0].length, 48000);
|
||||
buf.copyToChannel(audio[0], 0);
|
||||
buf.copyToChannel(audio[1], 1);
|
||||
audioSource = audioCtx.createBufferSource();
|
||||
audioSource.buffer = buf;
|
||||
audioSource.connect(gainNode);
|
||||
audioSource.playbackRate.setValueAtTime(state.playbackRate, audioCtx.currentTime);
|
||||
startAt = Math.max(audioCtx.currentTime, startAt);
|
||||
audioSource.start(startAt);
|
||||
startAt += buf.duration / state.playbackRate;
|
||||
}
|
||||
}
|
||||
|
||||
state.playing = true;
|
||||
state.paused = false;
|
||||
intervalId = setInterval(frameHandler, 1000 / 60); // 约60fps
|
||||
}
|
||||
|
||||
async function preview(time) {
|
||||
const { video } = await clip.tick(time * 1e6);
|
||||
if (video) {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
video.close();
|
||||
}
|
||||
}
|
||||
|
||||
function resize() {
|
||||
const player = art.template?.$player;
|
||||
if (!player || option.autoSize) return;
|
||||
|
||||
const aspectRatio = canvas.videoWidth / canvas.videoHeight;
|
||||
const containerWidth = player.clientWidth;
|
||||
const containerHeight = player.clientHeight;
|
||||
const containerRatio = containerWidth / containerHeight;
|
||||
|
||||
let paddingLeft = 0;
|
||||
let paddingTop = 0;
|
||||
|
||||
if (containerRatio > aspectRatio) {
|
||||
const canvasWidth = containerHeight * aspectRatio;
|
||||
paddingLeft = (containerWidth - canvasWidth) / 2;
|
||||
} else {
|
||||
const canvasHeight = containerWidth / aspectRatio;
|
||||
paddingTop = (containerHeight - canvasHeight) / 2;
|
||||
}
|
||||
|
||||
Object.assign(canvas.style, {
|
||||
padding: `${paddingTop}px ${paddingLeft}px`,
|
||||
});
|
||||
}
|
||||
|
||||
async function init() {
|
||||
const isSupported = await Combinator.isSupported();
|
||||
|
||||
if (!isSupported) {
|
||||
art.notice.show = 'WebAV is not supported';
|
||||
throw new Error('WebAV is not supported');
|
||||
}
|
||||
|
||||
stop();
|
||||
reset();
|
||||
|
||||
if (clip) {
|
||||
clip.destroy();
|
||||
art.emit('video:abort', { type: 'abort' });
|
||||
art.emit('video:emptied', { type: 'emptied' });
|
||||
}
|
||||
|
||||
try {
|
||||
await Promise.resolve();
|
||||
state.readyState = 1;
|
||||
art.emit('video:loadstart', { type: 'loadstart' });
|
||||
const response = await fetch(option.url);
|
||||
|
||||
if (!response.body) {
|
||||
throw new Error('No response body');
|
||||
}
|
||||
|
||||
clip = new MP4Clip(response.body, opt);
|
||||
} catch (error) {
|
||||
state.readyState = 0;
|
||||
art.emit('video:error', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const info = await clip.ready;
|
||||
|
||||
Object.assign(state, {
|
||||
readyState: 4,
|
||||
duration: Math.round(info.duration / 1e6),
|
||||
videoWidth: info.width,
|
||||
videoHeight: info.height,
|
||||
});
|
||||
|
||||
canvas.width = state.videoWidth;
|
||||
canvas.height = state.videoHeight;
|
||||
await preview(0.1);
|
||||
resize();
|
||||
|
||||
art.emit('video:loadedmetadata', { type: 'loadedmetadata' });
|
||||
art.emit('video:durationchange', { type: 'durationchange' });
|
||||
art.emit('video:loadeddata', { type: 'loadeddata' });
|
||||
art.emit('video:canplay', { type: 'canplay' });
|
||||
art.emit('video:canplaythrough', { type: 'canplaythrough' });
|
||||
}
|
||||
|
||||
def(canvas, 'duration', {
|
||||
get: () => state.duration,
|
||||
});
|
||||
|
||||
def(canvas, 'videoWidth', {
|
||||
get: () => state.videoWidth,
|
||||
});
|
||||
|
||||
def(canvas, 'videoHeight', {
|
||||
get: () => state.videoHeight,
|
||||
});
|
||||
|
||||
def(canvas, 'volume', {
|
||||
get: () => state.volume,
|
||||
set: (val) => {
|
||||
state.volume = Math.max(0, Math.min(1, val));
|
||||
updateVolume();
|
||||
art.emit('video:volumechange', { type: 'volumechange' });
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'currentTime', {
|
||||
get: () => state.currentTime,
|
||||
set: (val) => {
|
||||
if (state.readyState < 4) return;
|
||||
const newTime = Math.max(0, Math.min(val, state.duration));
|
||||
const now = performance.now();
|
||||
if (now - lastSeekTime > 16) {
|
||||
lastSeekTime = now;
|
||||
seekTarget = newTime;
|
||||
state.currentTime = newTime;
|
||||
if (!state.playing) {
|
||||
preview(newTime);
|
||||
}
|
||||
art.emit('video:timeupdate', { type: 'timeupdate' });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'autoplay', {
|
||||
get: () => state.autoplay,
|
||||
set: (val) => {
|
||||
state.autoplay = val;
|
||||
if (val && state.readyState >= 4) {
|
||||
canvas.play();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'src', {
|
||||
get: () => option.url,
|
||||
set: (val) => {
|
||||
option.url = val;
|
||||
init().then(() => {
|
||||
if (option.autoplay) {
|
||||
canvas.play();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'playbackRate', {
|
||||
get: () => state.playbackRate,
|
||||
set: (val) => {
|
||||
state.playbackRate = Math.max(0.25, Math.min(2, val));
|
||||
if (audioSource) {
|
||||
audioSource.playbackRate.setValueAtTime(state.playbackRate, audioCtx.currentTime);
|
||||
}
|
||||
art.emit('video:ratechange', { type: 'ratechange' });
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'playing', {
|
||||
get: () => state.playing,
|
||||
});
|
||||
|
||||
def(canvas, 'paused', {
|
||||
get: () => state.paused,
|
||||
});
|
||||
|
||||
def(canvas, 'ended', {
|
||||
get: () => state.ended,
|
||||
});
|
||||
|
||||
def(canvas, 'readyState', {
|
||||
get: () => state.readyState,
|
||||
});
|
||||
|
||||
def(canvas, 'muted', {
|
||||
get: () => state.muted,
|
||||
set: (val) => {
|
||||
state.muted = val;
|
||||
updateVolume();
|
||||
art.emit('video:volumechange', { type: 'volumechange' });
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'buffered', {
|
||||
get: () => ({
|
||||
start: () => 0,
|
||||
end: () => state.buffered,
|
||||
length: 1,
|
||||
}),
|
||||
});
|
||||
|
||||
def(canvas, 'play', {
|
||||
value: async () => {
|
||||
if (state.readyState < 4) return false;
|
||||
await play();
|
||||
art.emit('video:play', { type: 'play' });
|
||||
art.emit('video:playing', { type: 'playing' });
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
def(canvas, 'pause', {
|
||||
value: () => {
|
||||
stop();
|
||||
state.playing = false;
|
||||
state.paused = true;
|
||||
art.emit('video:pause', { type: 'pause' });
|
||||
},
|
||||
});
|
||||
|
||||
art.on('destroy', () => {
|
||||
stop();
|
||||
if (clip) {
|
||||
clip.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
art.on('resize', resize);
|
||||
|
||||
return canvas;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ type Option = {
|
||||
//
|
||||
};
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerProxyWebAV';
|
||||
};
|
||||
type Result = HTMLCanvasElement;
|
||||
|
||||
declare const artplayerProxyWebAV: (option: Option) => (art: Artplayer) => Result;
|
||||
@@ -53,7 +53,6 @@ console.info(art.template.$video);
|
||||
|
||||
- `proxy` 方法用于代理 `DOM` 事件
|
||||
- `hover` 方法用于代理自定义的 `hover` 事件
|
||||
- `loadImg` 方法用于监听图片的 `load` 加载事件
|
||||
|
||||
<div className="run-code">▶ Run Code</div>
|
||||
|
||||
@@ -74,10 +73,6 @@ art.events.hover(container, (event) => {
|
||||
}, (event) => {
|
||||
console.info('mouseleave', event);
|
||||
});
|
||||
|
||||
art.events.loadImg('/assets/sample/poster.jpg').then(img => {
|
||||
console.info('loadImg', img);
|
||||
});
|
||||
```
|
||||
|
||||
:::warning 提示
|
||||
|
||||
@@ -52,7 +52,6 @@ Manages all `DOM` events in the player, which is essentially a proxy for `addEve
|
||||
|
||||
- The `proxy` method is used to proxy `DOM` events
|
||||
- The `hover` method is used to proxy custom `hover` events
|
||||
- The `loadImg` method is used to listen for the `load` event of images
|
||||
|
||||
<div className="run-code">▶ Run Code</div>
|
||||
|
||||
@@ -73,10 +72,6 @@ art.events.hover(container, (event) => {
|
||||
}, (event) => {
|
||||
console.info('mouseleave', event);
|
||||
});
|
||||
|
||||
art.events.loadImg('/assets/sample/poster.jpg').then(img => {
|
||||
console.info('loadImg', img);
|
||||
});
|
||||
```
|
||||
:::warning Warning
|
||||
|
||||
|
||||
@@ -412,13 +412,13 @@ var art = new Artplayer({
|
||||
});
|
||||
```
|
||||
|
||||
| Hotkey | Description |
|
||||
| ------- | --------------------- |
|
||||
| `↑` | Increase volume |
|
||||
| `↓` | Decrease volume |
|
||||
| `←` | Fast forward video |
|
||||
| `→` | Rewind video |
|
||||
| `space` | Toggle play/pause |
|
||||
| Hotkey | Description |
|
||||
| ------- | ------------------ |
|
||||
| `↑` | Increase volume |
|
||||
| `↓` | Decrease volume |
|
||||
| `←` | Fast forward video |
|
||||
| `→` | Rewind video |
|
||||
| `space` | Toggle play/pause |
|
||||
|
||||
:::warning Tip
|
||||
|
||||
@@ -734,11 +734,11 @@ var art = new Artplayer({
|
||||
|
||||
Whether to show the `quality selection` list in the bottom control bar
|
||||
|
||||
| Property | Type | Description |
|
||||
| ---------- | --------- | -------------- |
|
||||
| `default` | `Boolean` | Default quality|
|
||||
| `html` | `String` | Quality name |
|
||||
| `url` | `String` | Quality URL |
|
||||
| Property | Type | Description |
|
||||
| --------- | --------- | --------------- |
|
||||
| `default` | `Boolean` | Default quality |
|
||||
| `html` | `String` | Quality name |
|
||||
| `url` | `String` | Quality URL |
|
||||
|
||||
<div className="run-code">▶ Run Code</div>
|
||||
|
||||
@@ -766,10 +766,10 @@ var art = new Artplayer({
|
||||
|
||||
Show `highlight information` on the progress bar
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | -------- | -------------------- |
|
||||
| `time` | `Number` | Highlight time (in seconds)|
|
||||
| `text` | `String` | Highlight text |
|
||||
| Property | Type | Description |
|
||||
| -------- | -------- | --------------------------- |
|
||||
| `time` | `Number` | Highlight time (in seconds) |
|
||||
| `text` | `String` | Highlight text |
|
||||
|
||||
<div className="run-code">▶ Run Code</div>
|
||||
|
||||
@@ -836,13 +836,14 @@ var art = new Artplayer({
|
||||
|
||||
Set `thumbnails` on the progress bar
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | -------- | ------------------- |
|
||||
| `url` | `String` | Thumbnail URL |
|
||||
| `number` | `Number` | Number of thumbnails|
|
||||
| `column` | `Number` | Columns of thumbnails|
|
||||
| `width` | `Number` | Thumbnail width |
|
||||
| `height` | `Number` | Thumbnail height |
|
||||
| Property | Type | Description |
|
||||
| -------- | -------- | --------------------- |
|
||||
| `url` | `String` | Thumbnail URL |
|
||||
| `number` | `Number` | Number of thumbnails |
|
||||
| `column` | `Number` | Columns of thumbnails |
|
||||
| `width` | `Number` | Thumbnail width |
|
||||
| `height` | `Number` | Thumbnail height |
|
||||
| `scale` | `Number` | Thumbnail scale |
|
||||
|
||||
<div className="run-code">▶ Run Code</div>
|
||||
|
||||
@@ -870,11 +871,11 @@ var art = new Artplayer({
|
||||
|
||||
Set the video subtitles, supporting subtitle formats: `vtt`, `srt`, `ass`
|
||||
|
||||
| Property | Type | Description |
|
||||
| ----------- | ---------- | ----------------------------------- |
|
||||
| `name` | `String` | Subtitle name |
|
||||
| `url` | `String` | Subtitle URL |
|
||||
| `type` | `String` | Subtitle type, options: `vtt`, `srt`, `ass` |
|
||||
| Property | Type | Description |
|
||||
| -------- | -------- | ------------------------------------------- |
|
||||
| `name` | `String` | Subtitle name |
|
||||
| `url` | `String` | Subtitle URL |
|
||||
| `type` | `String` | Subtitle type, options: `vtt`, `srt`, `ass` |
|
||||
|
||||
| `style` | `Object` | Subtitle style |
|
||||
| `encoding` | `String` | Subtitle encoding, default `utf-8` |
|
||||
|
||||
@@ -853,6 +853,7 @@ var art = new Artplayer({
|
||||
| `column` | `Number` | 预览图列数 |
|
||||
| `width` | `Number` | 预览图宽度 |
|
||||
| `height` | `Number` | 预览图高度 |
|
||||
| `scale` | `Number` | 预览图缩放 |
|
||||
|
||||
<div className="run-code">▶ Run Code</div>
|
||||
|
||||
@@ -883,7 +884,7 @@ var art = new Artplayer({
|
||||
|
||||
| 属性 | 类型 | 描述 |
|
||||
| ----------- | ---------- | ----------------------------------- |
|
||||
| `name` | `String` | 字幕名字 |
|
||||
| `name` | `String` | 字幕名字 |
|
||||
| `url` | `String` | 字幕地址 |
|
||||
| `type` | `String` | 字幕类型,可选 `vtt`, `srt`, `ass` |
|
||||
| `style` | `Object` | 字幕样式 |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ArtPlayerError } from '../utils/error';
|
||||
import clickInit from './clickInit';
|
||||
import hoverInit from './hoverInit';
|
||||
import moveInit from './moveInit';
|
||||
@@ -13,7 +12,6 @@ export default class Events {
|
||||
this.destroyEvents = [];
|
||||
this.proxy = this.proxy.bind(this);
|
||||
this.hover = this.hover.bind(this);
|
||||
this.loadImg = this.loadImg.bind(this);
|
||||
|
||||
clickInit(art, this);
|
||||
hoverInit(art, this);
|
||||
@@ -45,28 +43,6 @@ export default class Events {
|
||||
}
|
||||
}
|
||||
|
||||
loadImg(img) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let image;
|
||||
|
||||
if (img instanceof HTMLImageElement) {
|
||||
image = img;
|
||||
} else if (typeof img === 'string') {
|
||||
image = new Image();
|
||||
image.src = img;
|
||||
} else {
|
||||
return reject(new ArtPlayerError('Unable to get Image'));
|
||||
}
|
||||
|
||||
if (image.complete) {
|
||||
return resolve(image);
|
||||
}
|
||||
|
||||
this.proxy(image, 'load', () => resolve(image));
|
||||
this.proxy(image, 'error', () => reject(new ArtPlayerError(`Failed to load Image: ${image.src}`)));
|
||||
});
|
||||
}
|
||||
|
||||
remove(destroyEvent) {
|
||||
const index = this.destroyEvents.indexOf(destroyEvent);
|
||||
if (index > -1) {
|
||||
|
||||
@@ -170,6 +170,7 @@ export default class Artplayer extends Emitter {
|
||||
column: 10,
|
||||
width: 0,
|
||||
height: 0,
|
||||
scale: 1,
|
||||
},
|
||||
subtitle: {
|
||||
url: '',
|
||||
|
||||
@@ -8,6 +8,8 @@ export default function seekMix(art) {
|
||||
});
|
||||
|
||||
def(art, 'loadedTime', {
|
||||
get: () => ($video.buffered.length ? $video.buffered.end($video.buffered.length - 1) : 0),
|
||||
get: () => {
|
||||
return $video.buffered.length ? $video.buffered.end($video.buffered.length - 1) : 0;
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,9 @@ import { def } from '../utils';
|
||||
export default function playingMix(art) {
|
||||
const { $video } = art.template;
|
||||
def(art, 'playing', {
|
||||
get: () => !!($video.currentTime > 0 && !$video.paused && !$video.ended && $video.readyState > 2),
|
||||
get: () => {
|
||||
if (typeof $video.playing === 'boolean') return $video.playing;
|
||||
return !!($video.currentTime > 0 && !$video.paused && !$video.ended && $video.readyState > 2);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import { def, setStyle, isMobile } from '../utils';
|
||||
import { def, setStyle, isMobile, loadImg } from '../utils';
|
||||
|
||||
export default function thumbnailsMix(art) {
|
||||
const {
|
||||
option,
|
||||
events: { loadImg },
|
||||
template: { $progress, $video },
|
||||
} = art;
|
||||
|
||||
@@ -24,14 +23,14 @@ export default function thumbnailsMix(art) {
|
||||
const $thumbnails = art.controls?.thumbnails;
|
||||
if (!$thumbnails) return;
|
||||
|
||||
const { url, number, column, width, height } = option.thumbnails;
|
||||
const width2 = width || image.naturalWidth / column;
|
||||
const height2 = height || width2 / ($video.videoWidth / $video.videoHeight);
|
||||
const { number, column, width, height, scale } = option.thumbnails;
|
||||
const width2 = width * scale || image.naturalWidth / column;
|
||||
const height2 = height * scale || width2 / ($video.videoWidth / $video.videoHeight);
|
||||
const perWidth = $progress.clientWidth / number;
|
||||
const perIndex = Math.floor(posWidth / perWidth);
|
||||
const yIndex = Math.ceil(perIndex / column) - 1;
|
||||
const xIndex = perIndex % column || column - 1;
|
||||
setStyle($thumbnails, 'backgroundImage', `url(${url})`);
|
||||
setStyle($thumbnails, 'backgroundImage', `url(${image.src})`);
|
||||
setStyle($thumbnails, 'height', `${height2}px`);
|
||||
setStyle($thumbnails, 'width', `${width2}px`);
|
||||
setStyle($thumbnails, 'backgroundPosition', `-${xIndex * width2}px -${yIndex * height2}px`);
|
||||
@@ -46,7 +45,7 @@ export default function thumbnailsMix(art) {
|
||||
|
||||
art.on('setBar', async (type, percentage, event) => {
|
||||
const $thumbnails = art.controls?.thumbnails;
|
||||
const { url } = option.thumbnails;
|
||||
const { url, scale } = option.thumbnails;
|
||||
if (!$thumbnails || !url) return;
|
||||
|
||||
const isMobileDroging = type === 'played' && event && isMobile;
|
||||
@@ -54,7 +53,7 @@ export default function thumbnailsMix(art) {
|
||||
if (type === 'hover' || isMobileDroging) {
|
||||
if (!loading) {
|
||||
loading = true;
|
||||
image = await loadImg(url);
|
||||
image = await loadImg(url, scale);
|
||||
isLoad = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ export default function autoPlayback(art) {
|
||||
const $last = query('.art-auto-playback-last', $autoPlayback);
|
||||
const $jump = query('.art-auto-playback-jump', $autoPlayback);
|
||||
const $close = query('.art-auto-playback-close', $autoPlayback);
|
||||
append($close, icons.close);
|
||||
|
||||
let timer = null;
|
||||
|
||||
art.on('video:timeupdate', () => {
|
||||
if (art.playing) {
|
||||
@@ -35,11 +38,14 @@ export default function autoPlayback(art) {
|
||||
}
|
||||
});
|
||||
|
||||
art.on('ready', () => {
|
||||
function init() {
|
||||
const times = storage.get('times') || {};
|
||||
const currentTime = times[art.option.id || art.option.url];
|
||||
|
||||
clearTimeout(timer);
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
|
||||
if (currentTime && currentTime >= constructor.AUTO_PLAYBACK_MIN) {
|
||||
append($close, icons.close);
|
||||
setStyle($autoPlayback, 'display', 'flex');
|
||||
|
||||
$last.innerText = `${i18n.get('Last Seen')} ${secondToTime(currentTime)}`;
|
||||
@@ -57,12 +63,15 @@ export default function autoPlayback(art) {
|
||||
});
|
||||
|
||||
art.once('video:timeupdate', () => {
|
||||
setTimeout(() => {
|
||||
timer = setTimeout(() => {
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
}, constructor.AUTO_PLAYBACK_TIMEOUT);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
art.on('ready', init);
|
||||
art.on('restart', init);
|
||||
|
||||
return {
|
||||
name: 'auto-playback',
|
||||
|
||||
@@ -104,6 +104,7 @@ export default {
|
||||
column: n,
|
||||
width: n,
|
||||
height: n,
|
||||
scale: n,
|
||||
},
|
||||
subtitle: {
|
||||
url: s,
|
||||
|
||||
@@ -42,10 +42,11 @@ export default class Subtitle extends Component {
|
||||
}
|
||||
|
||||
get textTrack() {
|
||||
return this.art.template.$video.textTracks[0];
|
||||
return this.art.template.$video?.textTracks?.[0];
|
||||
}
|
||||
|
||||
get activeCue() {
|
||||
if (!this.textTrack) return null;
|
||||
return this.textTrack.activeCues[0];
|
||||
}
|
||||
|
||||
@@ -108,6 +109,7 @@ export default class Subtitle extends Component {
|
||||
template: { $subtitle },
|
||||
} = this.art;
|
||||
|
||||
if (!this.textTrack) return null;
|
||||
validator(subtitleOption, scheme.subtitle);
|
||||
if (!subtitleOption.url) return;
|
||||
this.style(subtitleOption.style);
|
||||
|
||||
@@ -117,3 +117,44 @@ export function supportsFlex() {
|
||||
export function getRect(el) {
|
||||
return el.getBoundingClientRect();
|
||||
}
|
||||
|
||||
export function loadImg(url, scale) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.crossOrigin = 'Anonymous';
|
||||
|
||||
img.onload = function () {
|
||||
if (!scale || scale === 1) {
|
||||
resolve(img);
|
||||
} else {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = img.width * scale;
|
||||
canvas.height = img.height * scale;
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
canvas.toBlob((blob) => {
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
const scaledImg = new Image();
|
||||
|
||||
scaledImg.onload = function () {
|
||||
resolve(scaledImg);
|
||||
};
|
||||
|
||||
scaledImg.onerror = function () {
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
reject(new Error(`Image load failed: ${url}`));
|
||||
};
|
||||
|
||||
scaledImg.src = blobUrl;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
img.onerror = function () {
|
||||
reject(new Error(`Image load failed: ${url}`));
|
||||
};
|
||||
|
||||
img.src = url;
|
||||
});
|
||||
}
|
||||
-1
@@ -118,7 +118,6 @@ declare class Artplayer extends Player {
|
||||
options?: boolean | AddEventListenerOptions,
|
||||
): () => void;
|
||||
hover(element: HTMLElement, mouseenter?: (event: Event) => any, mouseleave?: (event: Event) => any): void;
|
||||
loadImg(element: HTMLImageElement | string): Promise<HTMLImageElement>;
|
||||
remove(event: Event): void;
|
||||
};
|
||||
|
||||
|
||||
Vendored
+6
-1
@@ -34,6 +34,11 @@ export type Thumbnails = {
|
||||
* The thumbnail height
|
||||
*/
|
||||
height?: number;
|
||||
|
||||
/**
|
||||
* The thumbnail scale
|
||||
*/
|
||||
scale?: number;
|
||||
};
|
||||
|
||||
export type Option = {
|
||||
@@ -210,7 +215,7 @@ export type Option = {
|
||||
/**
|
||||
* Custom video proxy
|
||||
*/
|
||||
proxy?: null | ((this: Artplayer, art: Artplayer) => HTMLCanvasElement | HTMLVideoElement);
|
||||
proxy?: (this: Artplayer, art: Artplayer) => HTMLCanvasElement | HTMLVideoElement;
|
||||
|
||||
/**
|
||||
* Custom plugin list
|
||||
|
||||
Vendored
+1
@@ -54,4 +54,5 @@ export type Utils = {
|
||||
supportsFlex(): boolean;
|
||||
setStyleText(element: HTMLElement, text: string): void;
|
||||
getRect(el: HTMLElement): { top: number; left: number; width: number; height: number };
|
||||
loadImg(url: string, scale?: Number): Promise<HTMLImageElement>;
|
||||
};
|
||||
Reference in new issue
Block a user