全部產品
Search
文件中心

Intelligent Media Services:接入視訊剪輯Web SDK

更新時間:Aug 26, 2025

智能生產製作提供專業線上的視訊剪輯能力,針對自動化、智能化剪輯以及多人協作視頻製作需求,您可以基於時間軸進行雲剪輯。通過閱讀本文,您可以瞭解如何接入視訊剪輯Web SDK。

使用說明

本文中引入的視訊剪輯Web SDK的版本號碼5.2.2(僅供參考),從5.0.0開始,您需要申請License授權後使用剪輯Web SDK。擷取最新的版本資訊,請參見視訊剪輯工程——協助資訊

提交工單申請License。

操作步驟

  1. 引入視訊剪輯Web SDK。

    在專案前端分頁檔中的<head>標籤處引入視訊剪輯Web SDK的CSS檔案,如下所示:

    <head>
      <link rel="stylesheet" href="https://g.alicdn.com/thor-server/video-editing-websdk/5.2.2/index.css">
    </head>

    <body>標籤處添加一個用以掛載剪輯介面的<div>節點,並在<body>標籤末尾添加引入Web SDK的JS檔案,同時添加一個用以調用Web SDK的<script>節點。

    <body>
      <div id="aliyun-video-editor" style="height:700px"></div> // 您可以根據需要改變 container 高度
      <script src="https://g.alicdn.com/thor-server/video-editing-websdk/5.2.2/index.js"></script>
      <script>
        // 調用 SDK 的代碼放在這裡
      </script>
    </body>
  2. 初始化視訊剪輯Web SDK。

    window.AliyunVideoEditor.init(config);

config屬性說明

config參數

參數

類型

必填

描述

引入版本

locale

string

介面語言,取值:

  • zh-CN(預設值):中文。

  • en-US:英文。

3.0.0

container

Element

Web SDK產生介面掛載的DOM節點。

3.0.0

defaultAspectRatio

PlayerAspectRatio

預設的視頻預覽比例,預設為16∶9。

3.4.0

defaultSubtitleText

string

預設的字幕內容,不超過20個字元,預設為“阿里雲剪輯”。

3.6.0

useDynamicSrc

boolean

是否動態擷取資源資訊。

3.0.0

getDynamicSrc

(mediaId: string, mediaType: 'video' | 'audio' | 'image' | 'font', mediaOrigin?:'private' | 'public', inputUrl?: string) => Promise<string>;

動態擷取資源資訊,必填與否與參數useDynamicSrc一致。返回的Promise對象需要resolve資源新的資訊。

3.10.0

getEditingProjectMaterials

() => Promise<InputMedia[]>;

擷取工程關聯的素材。返回的Promise對象需要resolve所有素材類型的數組。

3.0.0

searchMedia

(mediaType: 'video' | 'audio' | 'image') => Promise<InputMedia[]>;

資產庫匯入素材按鈕相應函數。單擊匯入素材後會搜尋媒資資訊,將媒資庫媒資匯入到資產庫中。返回的Promise對象需要resolve新增素材的數組。

重要

您需要調用AddEditingProjectMaterials將新增的素材與工程關聯起來。

3.0.0

deleteEditingProjectMaterials

(mediaId: string, mediaType: 'video' | 'audio' | 'image') => Promise<void>;

解除綁定工程與素材。返回的Promise對象需要resolve。

3.0.0

submitASRJob

(mediaId: string, startTime: string, duration: string) => Promise<ASRResult[]>;

提交智能識別字幕任務。返回的Promise對象需要resolve識別的結果ASRResult數組。

3.1.0

推薦使用AsrConfig,使用AsrConfig會覆蓋submitASRJob方法。

submitAudioProduceJob

(text: string, voice: string, voiceConfig?: VoiceConfig) => Promise<InputMedia>;

提交文字轉語音任務,參數依次為:字幕內容、語音效果voice值和語音配置。返回的Promise對象需要resolve產生語音的資料。

4.3.5

推薦使用TTSConfig,使用TTSConfig會覆蓋submitAudioProduceJob方法。

licenseConfig

LicenseConfig

WebSDK的使用需要進行license配置。只有配置了license,才能線上上環境中使用WebSDK,如果沒有配置license,只能在localhost網域名稱下使用,在沒有配置license的情況下,在localhost使用會出現浮水印,而在線上上環境中進行預覽時會出現黑屏情況。

5.0.1

dynamicSrcQps

number

限制dynamicSrc的請求頻率。

4.13.0

getTimelineMaterials

(params: TimelineMaterial[]) => Promise<InputMedia[]>

擷取timeline中的素材媒資資訊,以用於擷取在getEditingProjectMaterials中未註冊的媒資,例如:第三方媒資。

4.13.4

asrConfig

AsrConfig

提交智能字幕任務的配置。

4.13.0

ttsConfig

TTSConfig

提交智能配音任務的配置。

5.0.1

disableAutoJobModal

boolean

關閉專案出現AI任務時自動開啟的彈窗。

5.0.1

disableGreenMatting

boolean

關閉綠幕摳圖入口。

4.13.0

disableRealMatting

boolean

關閉實景摳圖入口。

4.13.0

disableDenoise

boolean

關閉降噪入口。

4.13.0

audioWaveRenderDisabled

boolean

關閉波形圖渲染。

4.13.0

publicMaterials

PublicMaterialLibrary

公用素材庫配置。

4.13.0

subtitleConfig

SubtitleConfig

字幕背景漸層等配置。

4.13.0

getStickerCategories

() => Promise<StickerCategory[]>;

擷取貼紙分類,如果不傳,則不分類。返回的Promise對象需要resolve貼紙的分類數組。

3.0.0

getStickers

(config: {categoryId?: string; page: number; size: number}) => Promise<StickerResponse>;

擷取貼紙,如果貼紙沒有分類,則categoryId 為空白。返回的Promise對象需要resolve貼紙的總量和貼紙數組。

3.0.0

getEditingProject

() => Promise<{timeline?: Timeline; projectId?: string; modifiedTime?: string}>;

擷取工程的時間軸。返回的Promise對象需要resolve時間軸Timeline資料、專案ID和最後修改時間。

3.0.0

updateEditingProject

(data: {coverUrl: string; duration: number; timeline: Timeline; isAuto: boolean}) => Promise<{projectId: string}>;

儲存工程的時間軸,參數依次為:工程的封面圖地址、時間長度(單位:秒)、Timeline資料和是否自動儲存(當前每分鐘自動儲存1次)。返回的Promise對象需要resolve專案ID。

3.0.0

produceEditingProjectVideo

(data:{ coverUrl: string; duration: number; aspectRatio: PlayerAspectRatio; mediaMarks: MediaMark[]; timeline: Timeline; recommend: IProduceRecommend; }) => Promise<void>;

產生視頻,參數依次為:工程的封面圖地址、時間長度(單位:秒)、視頻比例、媒資標記、Timeline資料和recommend (視頻合成的解析度、碼率的推薦資料)。返回的Promise對象需要resolve。

4.4.0

customTexts

{importButton?:string;updateButton?:string;produceButton?:string;backButton?:string;logoUrl?:string;}

自訂部分文案,參數依次對應視訊剪輯介面的匯入素材儲存匯出視頻返回按鈕的文案和左上方Logo。

3.7.0

customFontList

Array<string | CustomFontItem>;

自訂字型類型。

3.10.0

customVoiceGroups

VoiceGroup[]

自訂語音選項。

4.3.5

getPreviewWaterMarks

() => Promise<Array<{ url?: string; mediaId?:string; width?: number; height?: number; x?: number; y?: number; xPlusWidth?: number; yPlusHeight?: number; opacity?: number; }>>;

預覽區添加浮水印,防止截屏(合成時沒有浮水印),參數如下所示:

  • url:浮水印圖片地址,與浮水印媒資ID二選一。

  • mediaId:浮水印媒資ID,與浮水印圖片地址二選一。

  • width:圖片的寬縮放百分比,範圍:(0,1],預設值為1,表示自適應預覽區。

  • height:圖片的高縮放百分比,範圍:(0,1],預設值為1,表示自適應預覽區。

  • x:圖片相對預覽區的x座標值,範圍:[0~1]。

  • y:圖片相對預覽區的y座標值,範圍:[0~1]。

  • xPlusWidth:圖片定位的左右位移參數,例如:圖片左右置中,則x=0.5,xPlusWidth=-0.5。

  • yPlusHeight:圖片定位的上下位移參數,例如:圖片左右置中,則y=0.5,yPlusHeight=-0.5。

  • opacity:圖片透明度。

4.3.5

exportVideoClipsSplit

(data: Array<{ coverUrl: string; duration: number; aspectRatio: PlayerAspectRatio; mediaMarks: MediaMark[]; timeline: Timeline; recommend?: IProduceRecommend; }>) => Promise<void>;

將選中Timeline的多個獨立片段拆分為不同Timeline並匯出,參數依次為:預設封面圖、匯出Timeline的時間長度、匯出比例、媒資標記、匯出的Timeline片段、視頻合成的解析度或碼率的推薦資料。

4.4.0

exportFromMediaMarks

(data: Array<{coverUrl: string; duration: number; aspectRatio: PlayerAspectRatio; mediaMarks: MediaMark[]; timeline:Timeline; recommend?: IProduceRecommend;}>,) => Promise<void>;

將選中Timeline的多個標記片段拆分為不同Timeline並匯出,參數依次為:預設封面圖、匯出Timeline的時間長度、匯出比例、媒資標記、匯出的Timeline片段、視頻合成的解析度或碼率的推薦資料。

4.4.5

exportVideoClipsMerge

(data: { coverUrl: string; duration: number; aspectRatio: PlayerAspectRatio; mediaMarks: MediaMark[]; timeline: Timeline; recommend?:IProduceRecommend; }) => Promise<void>;

將選中Timeline同一軌道的多個獨立片段合成為一個Timeline並匯出,參數依次為:預設封面圖、匯出Timeline的時間長度、匯出比例、媒資標記、匯出的Timeline片段、視頻合成的解析度或碼率的推薦資料。

4.4.0

getAudioByMediaId

(mediaId: string) =>Promise<string>;

擷取音頻地址,用於提升視頻的音訊波形圖繪製速度。傳入的參數為視頻素材ID,初始化時傳入該參數,SDK會優先使用其返回的音頻位址解析出視頻的音訊波形。返回的Promise對象需要resolve音頻地址URL。

4.3.5

hasTranscodedAudio

boolean

匯入工程中的所有視頻是否有代理音頻(轉碼後的音頻),取值:

  • true:所有匯入工程中的視頻素材都有代理音頻,SDK對於視頻分離音頻軌操作不會限制視頻素材原始時間長度。

    重要

    為了提升視頻分離音頻軌的效能,如果使用動態資源地址,則介面getDynamicSrc根據mediaType返回相應類型的資源資訊;如果使用靜態資源地址,則在Media.video.agentAudioSrc聲明視頻素材的代理音頻地址。

  • false:視頻分離音頻軌操作僅對原始時間長度不超過30分鐘的視頻素材開放。

4.3.6

avatarConfig

AvatarConfig

數字人接入配置。

4.10.0

disableAutoAspectRatio

boolean

是否關閉根據素材解析度切換比例彈窗。

4.12.2

videoTranslation

VideoTranslation

視頻翻譯相關配置

5.1.0

資料結構說明

  • PlayerAspectRatio

    enum PlayerAspectRatio {
      w1h1 = '1:1',
      w2h1 = '2:1',
      w4h3 = '4:3',
      w3h4 = '3:4',
      w9h16 = '9:16',
      w16h9 = '16:9',
      w21h9 = '21:9',
    }
  • VoiceConfig

    interface VoiceConfig {
      volume: number; // 音量,取值0~100,預設值50
      speech_rate: number; // 語速,取值範圍:-500~500,預設值:0
      pitch_rate: number; // 語調,取值範圍:-500~500,預設值:0
      format?: string; // 輸出檔案格式,支援:PCM/WAV/MP3
    }
  • InputMedia

     type InputMedia = (InputVideo | InputAudio | InputImage)
    
    interface InputSource {
      sourceState?: 'ready' | 'loading' | 'fail';
    }
    
    type MediaIdType = 'mediaId' | 'mediaURL';
    
    interface SpriteConfig {
      num: string;
      lines: string;
      cols: string;
      cellWidth?: string;
      cellHeight?: string;
    }
    
    interface MediaMark {
      startTime: number;
      endTime: number;
      content: string;
    }
    
    interface InputVideo extends InputSource {
      mediaId: string;
      mediaIdType?: MediaIdType;
      mediaType: 'video';
      video: {
        title: string;
        coverUrl?: string;
        duration: number;
        format?: string;
        src?: string;
        snapshots?: string[];
        sprites?: string[];
        spriteConfig?: SpriteConfig;
        width?: number;
        height?: number;
        rotate?: number;
        bitrate?: number;
        fps?: number;
        hasTranscodedAudio?: true;
        agentAudioSrc?: string;
        marks?: MediaMark[];
        codec?: string;
      };
    }
     interface InputAudio extends InputSource {
      mediaId: string;
      mediaIdType?: MediaIdType;
      mediaType: 'audio';
      audio: {
        title: string;
        duration: number;
        coverUrl?: string;
        src?: string;
        marks?: MediaMark[];
        formatNames?: string[];
      };
    }
     interface InputImage extends InputSource {
      mediaId: string;
      mediaIdType?: MediaIdType;
      mediaType: 'image';
      image: {
        title: string;
        coverUrl?: string;
        src?: string;
        width?: number;
        height?: number;
        rotate?: number;
      };
    }
    
    type TimelineMaterial = { mediaIdType: MediaIdType; mediaId: string; mediaType: MediaType };
  • MediaMark

    interface MediaMark {
      startTime: number;
      endTime: number;
      content: string;
    }
  • ASRResult

    interface ASRResult {
      content: string; // 字幕的內容
      from: number; // 字幕的開始相對於識別素材的開始的時間位移量
      to: number; // 字幕的結束相對於識別素材的開始的時間位移量
    }
  • StickerCategory

    interface StickerCategory {
      id: string; // 分類的 id
      name: string; // 分類的名稱,調用者自行切換語言
    }
  • StickerResponse

    interface Sticker {
      mediaId: string;
      src: string;
    }
      
    interface StickerResponse {
      total: number;
      stickers: Sticker[];
    }
  • IProduceRecommend

    interface IProduceRecommend {
      width?: number;
      height?: number;
      bitrate?: number;
    }
  • CustomFontItem

    interface CustomFontItem {
      key: string; // 字型唯一標識
      name?: string; // 展示的名字,沒有用key
      url: string; // 字型地址
      // 用於前、後端字型渲染保持一致,頁面文字渲染大小是您設定的字型大小乘以這個倍數
      fontServerScale?: {
        // 普通字幕字型倍數
        common: number;
        // 花字字型倍數
        decorated: number;
      };
    }
  • VoiceGroup

    export interface VoiceGroup {
      type: string; // 分類
      category:string; // 主分類
      voiceList?: Voice[];
      emptyContent?: {
        description: string;
        linkText: string;
        link: string;
      };
      getVoiceList?: (page: number, pageSize: number) => Promise<{ items: Voice[]; total: number }>;
      getVoice?: (voiceId: string) => Promise<Voice | null>;
      getDemo?: (mediaId: string) => Promise<{ src: string }>;
    }
  • Voice

    export interface Voice {
      voiceUrl?: string; // 樣本音頻地址
      demoMediaId?: string; // 樣本音訊播放地址
      voiceType: VoiceType; // 類型
      voice: string; // 人聲 key
      name: string; // “人名”
      desc: string; // 簡介
      tag?: string; // 標籤
      remark?: string; // 備忘支援的語言等資訊
      custom?: boolean; // 是否專屬人聲
    }
  • VoiceType

    enum VoiceType {
      Male = 'Male', // 男聲
      Female = 'Female', // 女聲
      Boy = 'Boy', // 男孩童聲
      Girl = 'Girl', // 女孩童聲
    }
  • AvatarConfig

    // 數字人配置說明
    interface AvatarConfig {
    // 數字人列表
      getAvatarList: () => DigitalHumanList[];
    
      // 提交數字人任務
      submitAvatarVideoJob: <T extends keyof DigitalHumanJobParamTypes>(
        job: DigitalHumanJob<T>,
      ) => Promise<DigitalHumanJobInfo>;
    
      // 擷取數字人任務結果
      getAvatarVideoJob: (jobId: string) => Promise<DigitalHumanJobResult>;
    
      // 任務輪詢時間
      refreshInterval: number;
      // 數字人輸出視頻配置
      outputConfigs: Array<{
        width: number;
        height: number;
        bitrates: number[];
      }>;
    
      filterOutputConfig?: (
        item: DigitalHuman,
        config:  Array<{
        width: number;
        height: number;
        bitrates: number[];
      }>,
      ) =>  Array<{
        width: number;
        height: number;
        bitrates: number[];
      }>;
    
    }
    
    // 數字人詳細類型說明
    
    // 數字人蔘數
    interface DigitalHuman {
      avatarId: string; // 數字人ID
      avatarName: string; // 數字人名稱
      coverUrl: string; // 數字人封面
      videoUrl?: string; // 數字人視頻demo地址
      outputMask?: boolean; // 是否輸出遮罩
      transparent?: boolean; // 是否背景透明
    }
    // 數字人列表
    interface DigitalHumanList {
      default: boolean;
      id: string;
      name: string;
      getItems: (pageNo: number, pageSize: number) => Promise<{ total: number; items: DigitalHuman[] }>;
    }
    // 數字人提交任務返回的資訊
    interface DigitalHumanJobInfo {
      jobId: string;
      mediaId: string;
    }
    
    // 數字人任務參數類型
     type DigitalHumanJobParamTypes = {
      text: {//文字驅動
        text?: string;
        params?: DigitalHumanTextParams;
        output?: DigitalHumanOutputParams;
      };
      audio: {//音頻檔案驅動
        mediaId?: string;
        params?: DigitalHumanAudioParams;
        output?: DigitalHumanOutputParams;
      };
    };
    
    // text|audio
    type DigitalHumanJobType = keyof DigitalHumanJobParamTypes;
    
    // 數字人文字驅動任務參數
    type DigitalHumanTextParams = {
      voice: string;
      volume: number;
      speechRate: number;
      pitchRate: number;
      autoASRJob?: boolean;
    };
    
    // 數字人音頻檔案驅動任務參數
    type DigitalHumanAudioParams = {
      title: string;
      autoASRJob?: boolean;
    };
    // 數字人輸出視頻其他參數
     type DigitalHumanOutputParams = {
      bitrate: number;
      width: number;
      height: number;
    };
    // 產生數字人字幕切片類型
    type SubtitleClip = { from: number; to: number; content: string };
    
    // 數字人任務運行輪詢結果
    interface DigitalHumanJobResult {
      jobId: string;
      mediaId: string;
      done: boolean;
      errorMessage?: string;
      job?: DigitalHumanJob<any>;
      video?: InputVideo;
      subtitleClips?: SubtitleClip[];
    }
    
    // 數字人任務
    type DigitalHumanJob<T extends DigitalHumanJobType> = {
      type: T;
      title: string;
      avatar: DigitalHuman;
      data: DigitalHumanJobParamTypes[T];
    };
    
    // 數字人產生視頻
    interface InputVideo {
      mediaId: string;
      mediaType: 'video';
      video: {
        title: string;
        coverUrl?: string;
        duration: number;
        src?: string; // 當 useDynamicUrl 為 true 時,src 可以不傳
        snapshots?: string[];
        sprites?: string[];
        spriteConfig?: SpriteConfig;//精靈圖
        width?: number; // 視頻源的寬度
        height?: number; // 視頻源的高度
        rotate?: number; // 視頻源的旋轉角度
        bitrate?: number; // 視頻源的碼率
        fps?: number; // 視頻源的幀率
        hasTranscodedAudio?: true; // 是否含有轉碼後的音頻流
        agentAudioSrc?: string; // 代理的音頻地址(用於分離音頻軌),當 useDynamicUrl 為 true 時,agentAudioSrc 可以不傳
        marks?: MediaMark[];// 視頻標記
      };
    }
  • LicenseConfig

    // license的配置
    type LicenseConfig = {
        rootDomain?: string; // license使用的根網域名稱,例如使用的網域名稱是 editor.abc.com,這裡填的值就是abc.com
        licenseKey?: string; // 申請的licenseKey,參考頂部使用說明在控制台中申請
     }
  • AsrConfig

    // 智能產生字幕的配置
    type AsrConfig = {
        interval?: number; // 輪詢時間長度,單位:毫秒
        defaultText?: string; // 預設的文案
        maxPlaceHolderLength?: number; // 預設的文案最大長度
        submitASRJob: (mediaId: string, startTime: string, duration: string) => Promise<ASRJobInfo>;
        getASRJobResult?: (jobId: string) => Promise<ASRJobInfo>;
     }
    interface ASRJobInfo {
      jobId?: string;
      jobDone: boolean;
      jobError?: string;
      result?: ASRResult[];
    }
  • TTSConfig

    // 智能配音任務的配置
    type TTSConfig = {
        interval?: number;  // 輪詢時間長度,單位:毫秒
        submitAudioProduceJob: (text: string, voice: string, voiceConfig?: VoiceConfig) => Promise<TTSJobInfo>;
        getAudioJobResult?: (jobId: string) => Promise<TTSJobInfo>;
     }
    interface VoiceConfig {
      volume: number;
      speech_rate: number;
      pitch_rate: number;
      format?: string;
      custom?: boolean;
    }
    
    interface TTSJobInfo {
      jobId?: string;
      jobDone: boolean;
      jobError?: string;
      asr?: AudioASRResult[];
      result?: InputAudio | null;
    }
    
    interface AudioASRResult {
      begin_time?: string;
      end_time?: string;
      text?: string;
      content?: string;
      from?: number;
      to?: number;
    }
  • PublicMaterialLibrary

    // 公用媒資庫的配置
    type PublicMaterialLibrary = {
      getLists: () => Promise<MaterialList[]>;
      name?: string;
      pageSize?: number; // 單頁展示數量
    };
     type MaterialList = {
      name?: string; 
      key: string;
      tag?: string;
      mediaType: 'video' | 'audio' | 'image';
      styleType?: 'video' | 'audio' | 'image' | 'background';
      getItems: (
        pageIndex: number,
        pageSize: number,
      ) => Promise<{
        items: InputMedia[];
        end: boolean;
      }>;
    };
  • SubtitleConfig

    type SubtitleConfig = {
         // 自訂紋理列表
        customTextures?: {  
          list: () => Promise<
            Array<{
              key: string;
              url: string;
            }>
          >;
          // 添加自訂紋理
          onAddTexture: () => Promise<{
            key: string;
            url: string;
          }>;
          // 刪除自訂紋理
          onDeleteTexture: (key: string) => Promise<void>;
        };
    }
  • AliyunVideoEditor

    // AliyunVideoEditor 執行個體方法
    type AliyunVideoEditor = {
        init: (config: IConfig) => void; // 初始化編輯器
        destroy: (keepState?: boolean) => boolean; // 銷毀編輯器
        version: string | undefined; // 擷取編輯器版本
        setCurrentTime: (currentTime: number) => void; // 設定編輯器預覽時間
        getCurrentTime: () => number; // 擷取編輯器預覽時間
        getDuration: () => number; // 擷取編輯器時間長度
        addProjectMaterials: (materials: InputMedia[]) => void; // 添加專案素材到編輯器
        setProjectMaterials: (materials: InputMedia[]) => void; // 設定專案素材到編輯器
        updateProjectMaterials: (update: (materials: InputMedia[]) => InputMedia[]) => void; // 更新編輯器當前專案素材
        deleteProjectMaterial: (mediaId: string) => void; // 刪除編輯器專案素材
        setProjectTimeline: ({ VideoTracks, AudioTracks, AspectRatio }: CustomTimeline) => Promise<void>; // 設定編輯器的timeline
        getProjectTimeline: () => any; // 擷取編輯器的timeline
        getEvents: (eventType?: 'ui' | 'player' | 'error' | 'websdk' | 'timeline') => IObservable<EventData<any>>; // 擷取編輯器的事件
        importSubtitles: (type: 'ass' | 'srt' | 'clip' | 'asr', config: string) => void; // 大量匯入字幕到編輯器
    }
  • VideoTranslation

    type VideoTranslation = {
      language?: {
        // 源語言
        source: Array<{
          value: string;
          label: string;
        }>;
        // 目標語言
        target: Array<{
          value: string;
          label: string;
        }>;
      };
      // 視頻翻譯
      translation?: {
        interval?: number;
        submitVideoTranslationJob: (params: TranslationJobParams) => Promise<TranslationJobInfo>;
        getVideoTranslationJob: (jobId: string) => Promise<TranslationJobInfo>;
      };
      // 字幕擦除
      detext?: {
        interval?: number;
        submitDetextJob: (param: DetextJobParams) => Promise<DetextJobInfo>;
        getDetextJob: (jobId: string) => Promise<DetextJobInfo>;
      };
      // 字幕提取
      captionExtraction?: {
        interval?: number;
        submitCaptionExtractionJob: (param: CaptionExtractionJobParams) => Promise<CaptionExtractionJobInfo>;
        getCaptionExtractionJob: (jobId: string) => Promise<CaptionExtractionJobInfo>;
      };
    };
    
     interface TranslationJobParams {
        type: 'Video' | 'Text' | 'TextArray';
        mediaId?: string;
        mediaIdType?: MediaIdType;
        text?: string;
        textArray?: string[];
        editingConfig: {
            SourceLanguage: string;
            TargetLanguage: string;
            DetextArea?: string;
            SupportEditing?: boolean;
            SubtitleTranslate?: {
                TextSource: 'OCR' | 'SubtitleFile';
                OcrArea?: string;
                SubtitleConfig?: string;
            };
        };
    }
    
    interface TranslationJobInfo {
        jobId?: string;
        jobDone: boolean;
        jobError?: string;
        result?: {
            video?: InputVideo;
            timeline?: string;
            text?: string;
            textArray?: Array<{
                Target: string;
                Source: string;
            }>;
        };
    }
    
    interface DetextJobParams {
        mediaId: string;
        mediaIdType: MediaIdType;
        box?: 'auto' | Array<[number, number, number, number]>;
    }
    
    interface DetextJobInfo {
        jobId?: string;
        jobDone: boolean;
        jobError?: string;
        result?: {
            video?: InputVideo;
        };
    }
    
    interface CaptionExtractionJobParams {
        mediaId: string;
        mediaIdType: MediaIdType;
        box?: 'auto' | Array<[number, number, number, number]>;
    }
    
    interface CaptionExtractionJobInfo {
        jobId?: string;
        jobDone: boolean;
        jobError?: string;
        result?: {
            srtContent?: string;
        };
    }

init()範例程式碼

重要

Web SDK只負責介面互動,不會發起請求,您需要通過Web SDK調用請求邏輯。請求本身應該先發送給您自己的服務端,您自己的服務端再根據AccessKey資訊(AccessKey ID和AccessKey Secret)轉寄給相關的阿里雲OpenAPI。

// 注意,WebSDK 本身並不提供 request 這個方法,這裡僅作為樣本,您可以使用您喜歡的網路請求庫,如 axios 等

window.AliyunVideoEditor.init({
  container: document.getElementById('aliyun-video-editor'),
  locale: 'zh-CN',
  licenseConfig: {
     rootDomain: "", // license使用的根網域名稱,例如abc.com
     licenseKey: "", // 申請的licenseKey,沒有配置licenseKey,在預覽時會出現浮水印,沒有配置license的情況下,只能在localhost的網域名稱下預覽
  },
  useDynamicSrc: true, // 媒資庫預設情況下播放地址會到期,所以需要動態擷取
  getDynamicSrc: (mediaId, mediaType) => new Promise((resolve, reject) => {
    request('GetMediaInfo', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-getmediainfo
      MediaId: mediaId
    }).then((res) => {
      if (res.code === '200') {
        // 注意,這裡僅作為樣本,實際中建議做好錯誤處理,避免如 FileInfoList 為空白數組時報錯等異常情況
        resolve(res.data.MediaInfo.FileInfoList[0].FileBasicInfo.FileUrl);
      } else {
        reject();
      }
    });
  }),
  getEditingProjectMaterials: () => {
    if (projectId) { // 如果沒有 projectId,需要先在智能媒體服務控制台建立剪輯工程,擷取projectId。
      return request('GetEditingProjectMaterials', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-geteditingprojectmaterials
        ProjectId: projectId
      }).then((res) => {
        const data = res.data.MediaInfos;
        return transMediaList(data); // 需要做一些資料變換,具體參考後文
      });
    }
    return Promise.resolve([]);
  },
  searchMedia: (mediaType) => { // mediaType 為使用者當前所在的素材 tab,可能為 video | audio | image,您可以根據這個參數對應地展示同類型的可添加素材
    return new Promise((resolve) => {
      // 調用方需要自己實現展示媒資、選擇媒資添加的介面,這裡的 callDialog 只是一種樣本,WebSDK 本身並不提供
      // 關於展示媒資,請參考:https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-listmediabasicinfos
      callDialog({
        onSubmit: async (materials) => {
          if (!projectId) { // 如果沒有 projectId,需要先建立工程,如果能確保有 projectId,則不需要該步
            const addRes = await request('CreateEditingProject', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-createeditingproject
              Title: 'xxxx',
            });
            projectId = addRes.data.Project.ProjectId;
          }

          // 組裝資料
          const valueObj = {};
          materials.forEach(({ mediaType, mediaId }) => {
            if (!valueObj[mediaType]) {
              valueObj[mediaType] = mediaId;
            } else {
              valueObj[mediaType] += mediaId;
            }
          })
          const res = await request('AddEditingProjectMaterials', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-addeditingprojectmaterials
            ProjectId: projectId,
            MaterialMaps: valueObj,
          });
          if (res.code === '200') {
            return resolve(transMediaList(res.data.MediaInfos));
          }
          resolve([]);
        }
      });
    });
  },
  deleteEditingProjectMaterials: async (mediaId, mediaType) => {
    const res = await request('DeleteEditingProjectMaterials', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-deleteeditingprojectmaterials
      ProjectId: projectId,
      MaterialType: mediaType,
      MaterialIds: mediaId
    });
    if (res.code === '200') return Promise.resolve();
    return Promise.reject();
  },
  getStickerCategories: async () => {
    const res = await request('ListAllPublicMediaTags', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-listallpublicmediatags
      BusinessType: 'sticker',
      WebSdkVersion: window.AliyunVideoEditor.version
    });

    const stickerCategories = res.data.MediaTagList.map(item => ({
      id: item.MediaTagId,
      name: myLocale === 'zh-CN' ? item.MediaTagNameChinese : item.MediaTagNameEnglish // myLocale 是您期望的語言
    }));
    return stickerCategories;
  },
  getStickers: async ({ categoryId, page, size }) => {
    const params = {
      PageNo: page,
      PageSize: size,
      IncludeFileBasicInfo: true,
      MediaTagId: categoryId
    };

    const res = await request('ListPublicMediaBasicInfos', params); // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-listpublicmediabasicinfos

    const fileList = res.data.MediaInfos.map(item => ({
      mediaId: item.MediaId,
      src: item.FileInfoList[0].FileBasicInfo.FileUrl
    }));

    return {
      total: res.data.TotalCount,
      stickers: fileList
    };
  },
  getEditingProject: async () => {
    if (projectId) {
      const res = await request('GetEditingProject', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-geteditingproject
        ProjectId: projectId
      });
      
      const timelineString = res.data.Project.Timeline;
   
      return {
        projectId,
        timeline: timelineString ? JSON.parse(timelineString) : undefined,
        modifiedTime: res.data.Project.ModifiedTime,
        title:res.data.Project.Title // 專案標題
      };
    }
    return {};
  },
  updateEditingProject: ({ coverUrl, duration, timeline, isAuto }) => new Promise((resolve, reject) => {
    request('UpdateEditingProject', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-updateeditingproject
      ProjectId: projectId,
      CoverURL: coverUrl,
      Duration: duration,
      Timeline: JSON.stringify(timeline)
    }).then((res) => {
      if (res.code === '200') {
        // WebSDK 本身會進行自動儲存,isAuto 則是告訴調用方這次儲存是否自動儲存,調用方可以控制只在手動儲存時才展示儲存成功的提示
        !isAuto && Message.success('儲存成功');
        resolve();
      } else {
        reject();
      }
    });
  }),
  produceEditingProjectVideo: ({ coverUrl, duration = 0, aspectRatio, timeline, recommend }) => {
    return new Promise((resolve) => {
      callDialog({ // 調用方需要自己實現提交合成任務的介面,這裡的 callDialog 只是一種樣本
        onSubmit: async ({ fileName, format, bitrate, description }) => { // 假設提交合成任務的介面讓你獲得了這些資料
          // 先根據 fileName 和 format 拼接出儲存的 mediaURL
          const mediaURL = `http://bucketName.oss-cn-hangzhou.aliyuncs.com/${fileName}.${format}`;
          // 根據 WebSDK 傳入的預覽比例來決定合成的寬高
          const width = aspectRatio === '16:9' ? 640 : 360;
          const height = aspectRatio === '16:9' ? 360 : 640;
          // 若視頻、圖片素材傳入的長寬、碼率等資料,那麼該函數返回的資料中的 recommend 就會包含了根據所使用的視頻、圖片計算得到的推薦的解析度和碼率
          // recommend 資料結構可以查看 IProduceRecommend
          // 你可以在提交介面上展示推薦資料或者直接使用在提交介面的參數裡
          const res = await request('SubmitMediaProducingJob', { // https://www.alibabacloud.com/help/zh/ims/developer-reference/api-ice-2020-11-09-submitmediaproducingjob
            OutputMediaConfig: JSON.stringify({
              mediaURL,
              bitrate: recommend.bitrate || bitrate,
              width: recommend.width || width,
              height: recommend.height || height
            }),
            OutputMediaTarget: 'oss-object',
            ProjectMetadata: JSON.stringify({ Description: description }),
            ProjectId: projectId,
            Timeline: JSON.stringify(timeline)
          });
          if (res.code === '200') {
            Message.success('產生視頻成功');
          }
          resolve();
        }
      });
    });
  }
});

/**
 * 將服務端的素材資訊轉換成 WebSDK 需要的格式
 */
function transMediaList(data) {
  if (!data) return [];

  if (Array.isArray(data)) {
    return data.map((item) => {
      const basicInfo = item.MediaBasicInfo;
      const fileBasicInfo = item.FileInfoList[0].FileBasicInfo;
      const mediaId = basicInfo.MediaId;
      const result = {
        mediaId
      };
      const mediaType = basicInfo.MediaType
      result.mediaType = mediaType;

      if (mediaType === 'video') {
        result.video = {
          title: fileBasicInfo.FileName,
          duration: Number(fileBasicInfo.Duration),
          // 源視頻的寬高、碼率等資料,用於推薦合成資料,不傳入或是0時無推薦資料
          width: Number(fileBasicInfo.Width) || 0,
          height: Number(fileBasicInfo.Height) || 0,
          bitrate: Number(fileBasicInfo.Bitrate) || 0,
          coverUrl: basicInfo.CoverURL
        };
        const spriteImages = basicInfo.SpriteImages
        if (spriteImages) {
          try {
            const spriteArr = JSON.parse(spriteImages);
            const sprite = spriteArr[0];
            const config = JSON.parse(sprite.Config);
            result.video.spriteConfig = {
              num: config.Num,
              lines: config.SpriteSnapshotConfig?.Lines,
              cols: config.SpriteSnapshotConfig?.Columns,
              cellWidth: config.SpriteSnapshotConfig?.CellWidth,
              cellHeight: config.SpriteSnapshotConfig?.CellHeight
            };
            result.video.sprites = sprite.SnapshotUrlList;
          } catch (e) {
            console.log(e);
          }
        }
      } else if (mediaType === 'audio') {
        result.audio = {
          title: fileBasicInfo.FileName,
          duration: Number(fileBasicInfo.Duration),
          coverURL: '' // 您可以給音頻檔案一個預設的封面圖
        }
      } else if (mediaType === 'image') {
        result.image = {
          title: fileBasicInfo.FileName,
          coverUrl: fileBasicInfo.FileUrl,
          // 圖片的寬高等資料,用於推薦合成資料,不傳入或是0時無推薦資料
          width: Number(fileBasicInfo.Width) || 0,
          height: Number(fileBasicInfo.Height) || 0,
        }
      }

      return result;
    });
  } else {
    return [data];
  }
}

相關參考

常見問題