refactor: Update loadedTime and playing getters in Artplayer

This commit is contained in:
Harvey Zack committed 2024-08-21 22:10:24 +08:00
1 parent 8613164368
commit 0a7d3ca5aa
3 files changed
+272 -176

No files matched your search

+132 -88
View File
@@ -147,89 +147,121 @@ var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
parcelHelpers.defineInteropFlag(exports);
parcelHelpers.export(exports, "default", ()=>artplayerProxyWebAV);
var _avCliper = require("@webav/av-cliper");
function artplayerProxyWebAV(option) {
function artplayerProxyWebAV() {
return (art)=>{
const { option, constructor } = art;
const { createElement, def } = constructor.utils;
const canvas = createElement("canvas");
const ctx = canvas.getContext("2d");
const audioCtx = new AudioContext();
let audioCtx;
let gainNode;
let clip = null;
let timer = null;
let audioSource = null;
let playing = false;
let duration = 0;
let videoWidth = 0;
let videoHeight = 0;
let currentTime = 0;
let loadedTime = 0;
let volume = 1;
let autoplay = false;
let playbackRate = 1;
let paused = true;
let ended = false;
let readyState = 0;
let muted = false;
const state = {
playing: false,
duration: 0,
videoWidth: 0,
videoHeight: 0,
currentTime: 0,
loadedTime: 0,
volume: 1,
autoplay: false,
playbackRate: 1,
paused: true,
ended: false,
readyState: 0,
muted: false
};
function reset() {
playing = false;
duration = 0;
videoWidth = 0;
videoHeight = 0;
currentTime = 0;
loadedTime = 0;
volume = 1;
autoplay = false;
playbackRate = 1;
paused = true;
ended = false;
readyState = 0;
muted = false;
Object.assign(state, {
playing: false,
duration: 0,
videoWidth: 0,
videoHeight: 0,
currentTime: 0,
loadedTime: 0,
volume: 1,
autoplay: false,
playbackRate: 1,
paused: true,
ended: false,
readyState: 0,
muted: false
});
}
function stop() {
clearInterval(timer);
audioSource?.stop();
if (audioSource) {
audioSource.stop();
audioSource = null;
}
}
function play() {
let curTime = currentTime * 1e6;
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;
stop();
updateVolume();
timer = setInterval(async ()=>{
const { state, video, audio } = await clip.tick(Math.round(curTime));
curTime += 1000 / 30 * 1000;
currentTime = curTime / 1e6;
const { state: clipState, video, audio } = await clip.tick(Math.round(curTime));
curTime += 1000 / 30 * 1000 * state.playbackRate;
state.currentTime = curTime / 1e6;
art.emit("video:timeupdate", {
type: "timeupdate"
});
if (state === "done") {
clearInterval(timer);
if (clipState === "done") {
stop();
state.ended = true;
state.playing = false;
state.paused = true;
art.emit("video:ended", {
type: "ended"
});
return;
}
if (video != null && state === "success") {
ctx.clearRect(0, 0, videoWidth, videoHeight);
ctx.drawImage(video, 0, 0, videoWidth, videoHeight);
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;
return;
}
const len = audio[0]?.length ?? 0;
if (len === 0) return;
const buf = audioCtx.createBuffer(2, len, 48000);
buf.copyToChannel(audio[0], 0);
buf.copyToChannel(audio[1], 1);
audioSource = audioCtx.createBufferSource();
audioSource.buffer = buf;
audioSource.connect(audioCtx.destination);
startAt = Math.max(audioCtx.currentTime, startAt);
audioSource.start(startAt);
startAt += buf.duration;
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;
}
}, 1000 / 30);
state.playing = true;
state.paused = false;
}
async function preview(time) {
const { video } = await clip.tick(time * 1e6);
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
if (video) {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
video.close();
}
}
async function init() {
stop();
@@ -244,28 +276,27 @@ function artplayerProxyWebAV(option) {
});
}
try {
await Promise.resolve();
art.emit("video:loadstart", {
type: "loadstart"
});
const response = await fetch(option.url);
if (!response.body) {
const error = new Error("No response body");
art.emit("video:error", error);
throw error;
}
if (!response.body) throw new Error("No response body");
clip = new (0, _avCliper.MP4Clip)(response.body);
} catch (error) {
art.emit("video:error", error);
throw error;
}
const info = await clip.ready;
readyState = 4;
duration = Math.round(info.duration / 1e6);
videoWidth = info.width;
videoHeight = info.height;
canvas.width = videoWidth;
canvas.height = videoHeight;
preview(0.1);
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);
art.emit("video:loadedmetadata", {
type: "loadedmetadata"
});
@@ -288,81 +319,94 @@ function artplayerProxyWebAV(option) {
]
});
def(canvas, "loadedTime", {
get: ()=>loadedTime
get: ()=>state.loadedTime
});
def(canvas, "duration", {
get: ()=>duration
get: ()=>state.duration
});
def(canvas, "videoWidth", {
get: ()=>videoWidth
get: ()=>state.videoWidth
});
def(canvas, "videoHeight", {
get: ()=>videoHeight
get: ()=>state.videoHeight
});
def(canvas, "volume", {
get: ()=>volume,
get: ()=>state.volume,
set: (val)=>{
volume = val;
state.volume = Math.max(0, Math.min(1, val));
updateVolume();
art.emit("video:volumechange", {
type: "volumechange"
});
}
});
def(canvas, "currentTime", {
get: ()=>currentTime,
get: ()=>state.currentTime,
set: (val)=>{
currentTime = val;
preview(val);
const newTime = Math.max(0, Math.min(val, state.duration));
state.currentTime = newTime;
preview(newTime);
if (state.playing) {
stop();
play();
}
art.emit("video:timeupdate", {
type: "timeupdate"
});
}
});
def(canvas, "autoplay", {
get: ()=>autoplay,
get: ()=>state.autoplay,
set: (val)=>{
autoplay = val;
state.autoplay = val;
if (val && state.readyState >= 4) canvas.play();
}
});
def(canvas, "src", {
get: ()=>option.url,
set: (val)=>{
option.url = val;
init();
init().then(()=>{
if (state.autoplay) canvas.play();
});
}
});
def(canvas, "playbackRate", {
get: ()=>playbackRate,
get: ()=>state.playbackRate,
set: (val)=>{
playbackRate = 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: ()=>playing
get: ()=>state.playing
});
def(canvas, "paused", {
get: ()=>paused
get: ()=>state.paused
});
def(canvas, "ended", {
get: ()=>ended
get: ()=>state.ended
});
def(canvas, "readyState", {
get: ()=>readyState
get: ()=>state.readyState
});
def(canvas, "muted", {
get: ()=>muted,
get: ()=>state.muted,
set: (val)=>{
muted = val;
state.muted = val;
updateVolume();
art.emit("video:volumechange", {
type: "volumechange"
});
}
});
// Define methods
def(canvas, "play", {
value: async ()=>{
play();
playing = true;
paused = false;
await play();
art.emit("video:play", {
type: "play"
});
@@ -374,8 +418,8 @@ function artplayerProxyWebAV(option) {
def(canvas, "pause", {
value: ()=>{
stop();
playing = false;
paused = true;
state.playing = false;
state.paused = true;
art.emit("video:pause", {
type: "pause"
});