import Artplayer from "artplayer"; import type { ComponentOption } from "artplayer/types/component.js"; import { ArtPlayer_PLUGIN_M4S_AUDIO_SUPPORT_KEY, type ArtPlayerPluginM4SAudioSupportEvent, type ArtPlayerPluginM4SAudioSupportResult, } from "./artplayer-plugin-bilibiliM4SAudioSupport"; import { ArtPlayer_PLUGIN_QUALITY_KEY, type ArtPlayerPluginQualityResult } from "./artplayer-plugin-quality"; export type ArtPlayerPluginVideoStatisticsOption = { data?: { key: string; value: string; }[]; }; export type ArtPlayerPluginVideoStatisticsResult = { name: string; /** * 更新参数时调用 * @param option */ update(option: ArtPlayerPluginVideoStatisticsOption): void; }; const TAG = "[artplayer-plugin-videoStatistics]:"; class VideoStatistics { art; option; $key = { plugin_KEY: "artplayer-plugin-videoStatistics", setting_name: "video-statistics", }; $data = { intervalId: undefined as number | undefined, }; constructor(art: typeof Artplayer.prototype, option: ArtPlayerPluginVideoStatisticsOption) { this.art = art; this.option = option; this.addSetting(); } /** * 添加设置面板菜单 */ addSetting() { this.art.setting.add({ name: this.$key.setting_name, icon: "", html: "视频统计信息", mounted: ($setting) => { let $leftIcon = $setting.querySelector(".art-setting-item-left-icon")!; $leftIcon.innerHTML = /*html*/ ` `.trim(); this.art.proxy( $setting, "click", (event) => { event.stopPropagation(); event.stopImmediatePropagation(); event.preventDefault(); this.art.setting.show = false; if (this.isRegisterLayer()) { this.updateLayer(); } else { this.showLayer(true); } }, { capture: true } ); }, }); } /** * 获取layer配置 */ getLayerOption(): ComponentOption { let mimeType: Required["data"][0] | undefined, audioHost: Required["data"][0] | undefined, audioTime: Required["data"][0] | undefined, resolution: Required["data"][0] = { key: "Resolution:", value: `${this.art.video.videoWidth} x ${this.art.video.videoHeight}`, }, videoDataRate: Required["data"][0] | undefined, audioDataRate: Required["data"][0] | undefined, audioDuration: Required["data"][0] | undefined; // 画质信息 let qualityPlugin = this.art.plugins[ArtPlayer_PLUGIN_QUALITY_KEY] as ArtPlayerPluginQualityResult | null; if (qualityPlugin) { let currentQualityOption = qualityPlugin.getCurrentQualityOption(); if (currentQualityOption) { mimeType = { key: "Mime Type:", value: `${currentQualityOption.mimeType}`, }; if (currentQualityOption.codecs.trim() !== "") { mimeType.value += `;codecs="${currentQualityOption.codecs}"`; } if (currentQualityOption.frameRate.trim() !== "") { resolution.value += "@" + currentQualityOption.frameRate; } if (currentQualityOption.bandwidth) { videoDataRate = { key: "Video DataRate:", value: (currentQualityOption.bandwidth / 1024).toFixed(0) + "Kbps", }; } } } // Audio信息 let m4sAudioPlugin = this.art.plugins[ ArtPlayer_PLUGIN_M4S_AUDIO_SUPPORT_KEY ] as ArtPlayerPluginM4SAudioSupportResult | null; if (m4sAudioPlugin) { let currentAudioOption = m4sAudioPlugin.getCurrentPlayConfig(); if (currentAudioOption) { audioHost = { key: "Audio Host:", value: new URL(currentAudioOption.url).host, }; audioTime = { key: "Audio Time:", value: m4sAudioPlugin.getAudio().currentTime.toString(), }; if (mimeType) { if (mimeType.value.trim() !== "") { mimeType.value += ", "; } mimeType.value += `${currentAudioOption.mimeType}`; if (currentAudioOption.codecs.trim() !== "") { mimeType.value += `;codecs="${currentAudioOption.codecs}"`; } } audioDataRate = { key: "Audio DataRate:", value: (currentAudioOption.bandwidth / 1024).toFixed(0) + "Kbps", }; audioDuration = { key: "Audio Duration:", value: m4sAudioPlugin.getAudio().duration.toString(), }; } } let data: (Required["data"][0] | undefined)[] = [ mimeType, { key: "Player Type", value: "ArtPlayer@" + Artplayer.version, }, resolution, videoDataRate, audioDataRate, { key: "Video Host:", value: new URL(this.art.url).host, }, audioHost, { key: "Video Time:", value: this.art.currentTime.toString(), }, audioTime, { key: "Video Duration:", value: this.art.duration.toString(), }, audioDuration, ]; data.push(...(this?.option?.data || [])); return { name: this.$key.setting_name, html: /*html*/ `
统计信息
${data .filter((it) => it != null) .map((item) => { return /*html*/ `
${item.key}
${item.value}
`; }) .join("\n")}
`, mounted: async ($topWrap) => { let $close = $topWrap.querySelector(".art-player-video-statistics-close svg")!; this.art.proxy($close, "click", (event) => { event.stopPropagation(); event.stopImmediatePropagation(); event.preventDefault(); this.closeLayer(); }); }, }; } /** * 判断是否已经注册过layer */ isRegisterLayer() { return this.$key.setting_name in this.art.layers; } /** * 显示layer * @param intervalUpdateInfo 是否定时刷新 */ showLayer(intervalUpdateInfo?: boolean) { clearInterval(this.$data.intervalId); let option = this.getLayerOption(); this.art.layers.add(option); if (intervalUpdateInfo) { this.unbindUpdateLayerEvent(); this.bindUpdateLayerEvent(); } } /** * 更新layer */ updateLayer() { let option = this.getLayerOption(); this.art.layers.update(option); } /** * 绑定layer更新事件 */ bindUpdateLayerEvent() { this.art.on("play", this.updateLayerEvent_interval, this); this.art.on("restart", this.updateLayerEvent_once, this); this.art.on( // @ts-ignore "m4sAudio:loadedmetadata" as ArtPlayerPluginM4SAudioSupportEvent, this.updateLayerEvent_once, this ); this.art.on("pause", this.updateLayerEvent_clear_interval, this); this.art.on("video:ended", this.updateLayerEvent_clear_interval, this); if (this.art.playing) { this.updateLayerEvent_interval(); } } /** * 取消绑定layer更新事件 */ unbindUpdateLayerEvent() { this.art.off("play", this.updateLayerEvent_interval); this.art.off("restart", this.updateLayerEvent_once); this.art.off( // @ts-ignore "m4sAudio:loadedmetadata" as ArtPlayerPluginM4SAudioSupportEvent, this.updateLayerEvent_once ); this.art.off("pause", this.updateLayerEvent_clear_interval); this.art.off("video:ended", this.updateLayerEvent_clear_interval); } /** * layer更新事件 */ updateLayerEvent_interval() { if (import.meta.hot) { console.log(TAG + "循环更新layer信息"); } clearInterval(this.$data.intervalId); this.$data.intervalId = setInterval(() => { this.updateLayer(); }, 1500); } /** * layer更新事件 */ updateLayerEvent_once() { if (import.meta.hot) { console.log(TAG + "更新layer信息一次"); } this.updateLayer(); } /** * layer停止更新事件 */ updateLayerEvent_clear_interval() { if (import.meta.hot) { console.log(TAG + "停止循环更新layer信息"); } clearInterval(this.$data.intervalId); } /** * 关闭layer */ closeLayer() { clearInterval(this.$data.intervalId); this.art.layers.remove(this.$key.setting_name); this.unbindUpdateLayerEvent(); } /** * 更新配置 */ update(option: ArtPlayerPluginVideoStatisticsOption) { this.option = option; } } export const artplayerPluginVideoStatistics = (option: ArtPlayerPluginVideoStatisticsOption) => { return (art: typeof Artplayer.prototype): ArtPlayerPluginVideoStatisticsResult => { let videoStatistics = new VideoStatistics(art, option); return { name: videoStatistics.$key.plugin_KEY, update(option: ArtPlayerPluginVideoStatisticsOption) { videoStatistics.update(option); }, }; }; };