index.vue 4.24 KB
<script lang="ts" setup>
  import { ComponentMode, ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
  import { option } from './config';
  import { BasicVideoPlay, getVideoTypeByUrl } from '/@/components/Video';
  import { computed, onMounted, onUnmounted, toRaw } from 'vue';
  import { VideoJsPlayerOptions } from 'video.js';
  import { AccessMode } from '/@/views/camera/manage/config.data';
  import { unref } from 'vue';
  import { closeFlvPlay, getFlvPlayUrl, getStreamingPlayUrl } from '/@/api/camera/cameraManager';
  import { ref } from 'vue';
  import { Spin } from 'ant-design-vue';
  import { useFingerprint } from '/@/utils/useFingerprint';
  import { isRtspProtocol } from '/@/components/Video/src/utils';
  import { isShareMode } from '/@/views/sys/share/hook';
  import { getJwtToken, getShareJwtToken } from '/@/utils/auth';

  const props = defineProps<{
    config: ComponentPropsConfigType<typeof option>;
  }>();

  const loading = ref(true);

  const basicVideoPlayEl = ref<Nullable<InstanceType<typeof BasicVideoPlay>>>(null);

  const withToken = ref(false);

  const playSource = ref<Record<'src' | 'type', string>>(
    {} as unknown as Record<'src' | 'type', string>
  );

  const exampleVideoPlay =
    'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm';

  const getOptions = computed<VideoJsPlayerOptions>(() => {
    return {
      width: '100%' as unknown as number,
      height: '100%' as unknown as number,
    };
  });

  const { getResult } = useFingerprint();

  const handleGetVideoPlayUrl = async () => {
    try {
      const { config } = props;
      const { option } = config;
      const { videoConfig, uuid } = option || {};
      if (!uuid) return;
      const { url, id, accessMode } = videoConfig || {};
      let type = getVideoTypeByUrl(url!);
      let playUrl = url;
      if (accessMode === AccessMode.Streaming && id) {
        const { data: { url } = { url: '' } } = await getStreamingPlayUrl(id!);
        playUrl = url;
        playUrl && (type = getVideoTypeByUrl(playUrl!));
      }

      if (isRtspProtocol(url!)) {
        const result = await getResult();
        const { visitorId } = result;
        playUrl = getFlvPlayUrl(playUrl!, visitorId);
        withToken.value = true;
      }

      playSource.value = {
        src: playUrl!,
        type,
      };

      const instance = unref(basicVideoPlayEl)?.customInit((options) => {
        if (unref(withToken)) {
          (options as any).flvjs.config.headers = {
            'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
          };
        }
        return { ...options, sources: [toRaw(unref(playSource))] } as VideoJsPlayerOptions;
      });

      instance?.play();
    } finally {
      loading.value = false;
    }
  };

  const handleSelectPreview = () => {
    loading.value = false;
    const instance = unref(basicVideoPlayEl)?.customInit((options) => {
      withToken.value = true;

      if (unref(withToken)) {
        (options as any).flvjs.config.headers = {
          'X-Authorization': `Bearer ${isShareMode() ? getShareJwtToken() : getJwtToken()}`,
        };
      }
      return {
        ...options,
        sources: [{ type: getVideoTypeByUrl(exampleVideoPlay), src: exampleVideoPlay }],
      } as VideoJsPlayerOptions;
    });
    instance?.play();
  };

  onMounted(() => {
    const { option } = props.config;
    const { mode } = option;
    mode === ComponentMode.SELECT_PREVIEW ? handleSelectPreview() : handleGetVideoPlayUrl();
  });

  onUnmounted(async () => {
    const { visitorId } = await getResult();
    const { option } = props.config;
    const { videoConfig } = option || {};
    const { url } = videoConfig || {};
    isRtspProtocol(url!) && closeFlvPlay(url!, visitorId);
  });
</script>

<template>
  <main class="w-full h-full flex flex-col justify-center items-center p-2">
    <Spin :spinning="loading" wrapper-class-name="video-spin">
      <BasicVideoPlay
        ref="basicVideoPlayEl"
        :options="getOptions"
        :with-token="withToken"
        :immediateInitOnMounted="false"
      />
    </Spin>
  </main>
</template>

<style lang="less" scoped>
  .video-spin {
    @apply w-full h-full;

    :deep(.ant-spin-container) {
      @apply w-full h-full;
    }
  }
</style>