Skip to content

Commit

Permalink
Feat: Refect sync plug
Browse files Browse the repository at this point in the history
  • Loading branch information
zijiren233 committed Oct 8, 2023
1 parent 7b6a7e7 commit 5801c0c
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 180 deletions.
14 changes: 4 additions & 10 deletions src/components/Player.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import Artplayer from "artplayer";
import type { Option } from "artplayer/types/option";
import { onMounted, onBeforeUnmount, ref, watch, computed } from "vue";
import type { PropType, WatchStopHandle } from "vue";
import artplayerPluginDanmuku from "artplayer-plugin-danmuku";
import mpegts from "mpegts.js";
import Hls from "hls.js";
import { deepEqualObject } from "@/utils/utils";
const room = roomStore();
const watchers: WatchStopHandle[] = [];
Expand All @@ -23,7 +23,8 @@ interface options {
url: string;
isLive: boolean;
type: string;
headers: Record<string, string>;
headers: { [key: string]: string };
plugins: ((art: Artplayer) => unknown)[];
}
const Props = defineProps({
Expand Down Expand Up @@ -178,13 +179,6 @@ const playerOption = computed<Option>(() => {
autoPlayback: false, // 使用自动回放功能
autoOrientation: true, // 移动端的网页全屏时,根据视频尺寸和视口尺寸,旋转播放器
airplay: false, // 隔空播放
plugins: [
artplayerPluginDanmuku({
// 弹幕数组
danmuku: [],
speed: 4
})
],
...Props.options,
customType: {
flv: playFlv,
Expand All @@ -211,7 +205,7 @@ onMounted(() => {
oldOption.isLive !== newOption.isLive ||
oldOption.type !== newOption.type ||
oldOption.url !== newOption.url ||
oldOption.headers !== newOption.headers
!deepEqualObject(oldOption.headers, newOption.headers)
);
};
Expand Down
243 changes: 119 additions & 124 deletions src/plugins/sync.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ref, watch } from "vue";
import type { WatchStopHandle } from "vue";
import type { WatchStopHandle, Ref } from "vue";
import { roomStore } from "@/stores/room";
import { devLog } from "@/utils/utils";
import { devLog, debounces } from "@/utils/utils";
import Notify from "@/utils/notify";
import { useDebounceFn } from "@vueuse/core";
import { WsMessageType } from "@/types/Room";
Expand All @@ -16,152 +16,139 @@ interface callback {
"ws-send": (msg: string) => void;
}

const debounceTime = 250;
interface resould {
plugin: (art: Artplayer) => unknown;
setAndNoPublishSeek: (seek: number) => void;
setAndNoPublishPlay: () => void;
setAndNoPublishPause: () => void;
setAndNoPublishRate: (rate: number) => void;
}

export const sync = (cbk: callback) => {
return (art: Artplayer) => {
if (!art.option.isLive) {
const publishSeek = useDebounceFn((currentTime: number) => {
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.SEEK,
Seek: currentTime,
Rate: art.playbackRate
})
);
devLog("视频空降,:", art.currentTime);
}, debounceTime);

const setAndNoPublishSeek = (seek: number) => {
art.currentTime = seek;
};

const publishPlayOrPause = useDebounceFn(() => {
// devLog("视频播放,seek:", art.currentTime);
if (art.playing) {
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.PLAY,
Seek: art.currentTime,
Rate: art.playbackRate
})
);
} else {
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.PAUSE,
Seek: art.currentTime,
Rate: art.playbackRate
})
);
}
}, debounceTime);

const setAndNoPublishPlayOrPause = (playing: boolean) => {
devLog("视频播放(no publish),seek:", art.currentTime);
if (playing) {
art.off("play", publishPlayOrPause);
art.once("play", () => {
art.on("play", publishPlayOrPause);
});
art.play().catch(() => {
art.muted = true;
art.play();
ElNotification({
title: "温馨提示",
type: "info",
message: "由于浏览器限制,播放器已静音,请手动开启声音"
});
});
} else {
art.off("pause", publishPlayOrPause);
art.once("pause", () => {
art.on("pause", publishPlayOrPause);
});
art.pause();
}
};

const publishRate = () => {
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.RATE,
Seek: art.currentTime,
Rate: art.playbackRate
})
);
devLog("视频倍速,seek:", art.currentTime);
};

const setAndNoPublishRate = (rate: number) => {
art.off("video:ratechange", publishRate);
art.once("video:ratechange", () => {
art.on("video:ratechange", publishRate);
});
art.playbackRate = rate;
};
const debounceTime = 500;

export const sync = (cbk: callback): resould => {
const debounce = debounces(debounceTime);
let player: Artplayer;
const publishSeek = useDebounceFn((currentTime: number) => {
if (player.option.isLive) return;
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.SEEK,
Seek: currentTime,
Rate: player.playbackRate
})
);
devLog("视频空降,:", player.currentTime);
}, debounceTime);

const setAndNoPublishSeek = (seek: number) => {
if (player.option.isLive || Math.abs(player.currentTime - seek) < 2) return;
player.currentTime = seek;
};

const publishPlay = () => {
if (player.option.isLive) return;
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.PLAY,
Seek: player.currentTime,
Rate: player.playbackRate
})
);
};

const publishPlayDebounce = debounce(publishPlay);

const setAndNoPublishPlay = () => {
if (player.option.isLive || player.playing) return;
player.off("play", publishPlayDebounce);
player.once("play", () => {
player.on("play", publishPlayDebounce);
});
player.play().catch(() => {
player.muted = true;
player.play();
ElNotification({
title: "温馨提示",
type: "info",
message: "由于浏览器限制,播放器已静音,请手动开启声音"
});
});
};

const publishPause = () => {
if (player.option.isLive) return;
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.PAUSE,
Seek: player.currentTime,
Rate: player.playbackRate
})
);
};

const publishPauseDebounce = debounce(publishPause);

const setAndNoPublishPause = () => {
if (player.option.isLive || !player.playing) return;
player.off("pause", publishPauseDebounce);
player.once("pause", () => {
player.on("pause", publishPauseDebounce);
});
player.pause();
};

const publishRate = () => {
if (player.option.isLive) return;
cbk["set-player-status"](
JSON.stringify({
Type: WsMessageType.RATE,
Seek: player.currentTime,
Rate: player.playbackRate
})
);
devLog("视频倍速,seek:", player.currentTime);
};

const setAndNoPublishRate = (rate: number) => {
if (player.option.isLive || player.playbackRate === rate) return;
player.off("video:ratechange", publishRate);
player.once("video:ratechange", () => {
player.on("video:ratechange", publishRate);
});
player.playbackRate = rate;
};

const plugin = (art: Artplayer) => {
player = art;
if (!art.option.isLive) {
art.once("ready", () => {
console.log(room.currentMovieStatus.seek);
setAndNoPublishSeek(room.currentMovieStatus.seek);
console.log("seek同步成功:", art.currentTime);

setAndNoPublishRate(room.currentMovieStatus.rate);
console.log("rate同步成功:", art.playbackRate);
setAndNoPublishPlayOrPause(room.currentMovieStatus.playing);
room.currentMovieStatus.playing ? setAndNoPublishPlay() : setAndNoPublishPause();
cbk["ws-send"]("PLAYER:视频已就绪");
});

art.on("play", publishPlayOrPause);
art.on("play", publishPlayDebounce);

// 视频暂停
art.on("pause", publishPlayOrPause);
art.on("pause", publishPauseDebounce);

// 空降
art.on("seek", publishSeek);

// 倍速
art.on("video:ratechange", publishRate);

const watchers: WatchStopHandle[] = [];

watchers.push(
watch(
() => room.currentMovieStatus.playing,
(playing, _) => {
devLog("play变了:", playing);
setAndNoPublishPlayOrPause(playing);
}
)
);

watchers.push(
watch(
() => room.currentMovieStatus.seek,
(seek) => {
if (Math.abs(seek - art.currentTime) < 2) return;
devLog("seek变了:", seek);
setAndNoPublishSeek(seek);
}
)
);

watchers.push(
watch(
() => room.currentMovieStatus.rate,
(rate) => {
devLog("rate变了:", rate);
setAndNoPublishRate(rate);
}
)
);

art.on("destroy", () => {
art.off("play", publishPlayOrPause);
art.off("pause", publishPlayOrPause);
art.off("play", publishPlayDebounce);
art.off("pause", publishPauseDebounce);
art.off("seek", publishSeek);
art.off("video:ratechange", publishRate);
watchers.forEach((watcher) => watcher());
});
} else {
art.once("ready", () => {
Expand All @@ -178,4 +165,12 @@ export const sync = (cbk: callback) => {
});
}
};

return {
plugin,
setAndNoPublishSeek,
setAndNoPublishPlay,
setAndNoPublishPause,
setAndNoPublishRate
};
};
4 changes: 2 additions & 2 deletions src/types/Movie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ export interface BaseMovieInfo {
proxy: boolean;
rtmpSource: boolean;
type: string;
headers: Record<string, string>;
headers: { [key: string]: string };
}

export interface EditMovieInfo {
id: number;
url: string;
name: string;
type: string;
headers: Record<string, string>;
headers: { [key: string]: string };
}

export interface MovieStatus {
Expand Down
37 changes: 37 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,40 @@ export const devLog = (...args: any[]) => {
console.log(...args);
}
};

export const debounces = (delay: number): Function => {
let timerId: ReturnType<typeof setTimeout> | null = null;

const add = (func: Function): Function => {
return (...args: any[]) => {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
func(...args);
timerId = null;
}, delay);
};
};

return add;
};

export const deepEqualObject = (obj1: any, obj2: any) => {
if (obj1 === obj2) {
return true;
} else if (
typeof obj1 === "object" &&
typeof obj2 === "object" &&
Object.keys(obj1).length === Object.keys(obj2).length
) {
for (const key in obj1) {
if (!deepEqualObject(obj1[key], obj2[key])) {
return false;
}
}
return true;
} else {
return false;
}
};
Loading

0 comments on commit 5801c0c

Please sign in to comment.