mirror of
https://github.com/langyuxiansheng/vue-aliplayer-v2.git
synced 2026-05-27 23:03:08 +08:00
fix: 升级vue3
This commit is contained in:
parent
cdf70ab208
commit
15c784daef
@ -1,2 +0,0 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
23
.eslintrc.js
23
.eslintrc.js
@ -1,23 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
browser: true,
|
||||
es6: true
|
||||
},
|
||||
'extends': [
|
||||
'plugin:vue/essential',
|
||||
'eslint:recommended'
|
||||
],
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
|
||||
globals: {
|
||||
'Aliplayer': false
|
||||
},
|
||||
}
|
||||
268
GITHUB_ISSUES_TODO.md
Normal file
268
GITHUB_ISSUES_TODO.md
Normal file
@ -0,0 +1,268 @@
|
||||
# GitHub Issues Todo
|
||||
|
||||
Fetched from `langyuxiansheng/vue-aliplayer-v2` open issues on 2026-05-23.
|
||||
|
||||
Source: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues
|
||||
|
||||
## Summary
|
||||
|
||||
- Open issues recorded: 25
|
||||
- Main themes: Vue 3 compatibility, SDK loading/lifecycle, FLV/HLS/RTMP playback, Aliplayer SDK version drift, skin/custom UI configuration, documentation gaps.
|
||||
- Implementation pass on 2026-05-23: Vue 3 rewrite landed, SDK default updated to the new `imp-web-player` path, wrapper-level lifecycle/loading/playback helpers were added. Items marked "Code status" below are handled in this repository unless noted as upstream/documentation-only.
|
||||
|
||||
## Compatibility And Packaging
|
||||
|
||||
### #34 please support vue3.x
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/34
|
||||
- Created: 2020-12-08
|
||||
- Comments: 3
|
||||
- Problem: users request Vue 3 support.
|
||||
- Notes: comments mention a third-party Vue 3/Vite fork/package `vue-aliplayer-v3`; current project is Vue 2 based.
|
||||
- Follow-up: decide whether to add Vue 3 support in this package, publish a separate Vue 3 package, or document Vue 2-only support.
|
||||
- Code status: fixed in v2.0.0 rewrite. Vue 2 users must stay on 1.x.
|
||||
|
||||
### #35 安装之后引用就直接报这个问题
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/35
|
||||
- Created: 2020-12-23
|
||||
- Comments: 3
|
||||
- Problem: Vue 3 usage throws `Cannot read property '_c' of undefined` from `vue-aliplayer-v2.umd.min.js`.
|
||||
- Notes: maintainer identified likely cause as Vue version mismatch; overlaps with #34.
|
||||
- Follow-up: treat as Vue 3 compatibility/package-entry issue.
|
||||
- Code status: fixed by replacing the Vue 2 UMD build with Vue 3/Vite library output.
|
||||
|
||||
### #65 VueAliplayerV2在vue中使用报错
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/65
|
||||
- Created: 2022-06-12
|
||||
- Comments: 1
|
||||
- Problem: user reports usage error with screenshot only.
|
||||
- Notes: another user reported the same issue in 2023.
|
||||
- Follow-up: inspect screenshot manually when triaging; likely packaging/import/runtime compatibility.
|
||||
- Code status: likely fixed by Vue 3 package rewrite and typed exports; still needs reporter repro if screenshot covers another error.
|
||||
|
||||
### #45 关于浏览器兼容的问题
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/45
|
||||
- Created: 2021-03-23
|
||||
- Comments: 1
|
||||
- Problem: works in Chrome 89, player component does not display in Chrome 59.
|
||||
- Notes: current wrapper relies on upstream Aliplayer SDK compatibility.
|
||||
- Follow-up: define supported browser matrix and test whether transpilation/polyfills or SDK version is the blocker.
|
||||
- Code status: documented as upstream SDK/browser support. v2 build targets modern Vue 3/Vite environments.
|
||||
|
||||
### #46 请问,我使用uniapp安装aliplayerV2的问题
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/46
|
||||
- Created: 2021-03-25
|
||||
- Comments: 1
|
||||
- Problem: using npm install in uni-app, player buttons/components do not show.
|
||||
- Notes: maintainer had not tested uni-app.
|
||||
- Follow-up: decide whether uni-app is supported; if yes, add setup notes and a minimal repro.
|
||||
- Code status: not claimed as fixed. Needs a uni-app repro because this package targets Vue 3 web apps.
|
||||
|
||||
### #70 建议升级阿里云播放器到最新版
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/70
|
||||
- Created: 2023-04-12
|
||||
- Comments: 0
|
||||
- Problem: default SDK is outdated; user changed CSS/JS defaults to Aliplayer `2.15.2`.
|
||||
- Notes: user also mentions missing source maps because Aliplayer is closed source.
|
||||
- Follow-up: verify latest stable Aliplayer SDK URL, update defaults if safe, and document how to override SDK URLs.
|
||||
- Code status: fixed. Default SDK now uses `apsara-media-box/imp-web-player/2.37.0`; `sdkVersion`, `cssLink`, and `scriptSrc` are configurable.
|
||||
|
||||
## SDK Loading And Lifecycle
|
||||
|
||||
### #71 优化建议
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/71
|
||||
- Created: 2024-08-02
|
||||
- Comments: 2
|
||||
- Problem: each created player reportedly adds another CSS and JS resource.
|
||||
- Notes: comment references newer `apsara-media-box/imp-web-player/2.16.3` resource URLs and a multi-player example.
|
||||
- Follow-up: reproduce with multiple create/destroy cycles and verify whether duplicate resource tags appear under current component logic.
|
||||
- Code status: fixed in shared SDK loader. It caches CSS/JS by URL and avoids duplicate tags for multiple players.
|
||||
|
||||
### #62 多屏播放后,只销毁最后一个播放实例
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/62
|
||||
- Created: 2022-03-25
|
||||
- Comments: 2
|
||||
- Problem: in `v-for`, clearing the list only destroys the last player instance.
|
||||
- Notes: reporter says FLV did not reproduce, HLS did reproduce.
|
||||
- Follow-up: test multi-instance destroy with HLS and inspect player ID/ref/lifecycle handling.
|
||||
- Code status: improved. Component now guards async init after unmount and disposes each instance independently; still needs real HLS multi-player regression test.
|
||||
|
||||
### #69 Uncaught TypeError: s._options is null
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/69
|
||||
- Created: 2023-03-29
|
||||
- Comments: 0
|
||||
- Problem: runtime error `s._options is null`, screenshot only.
|
||||
- Follow-up: inspect screenshot and try to reproduce around destroy/re-init or options mutation.
|
||||
- Code status: improved. Init is token-guarded and avoids creating stale players after fast option/source changes.
|
||||
|
||||
## Playback Failures And Stream Behavior
|
||||
|
||||
### #11 rtmp html5模式下不能播放
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/11
|
||||
- Created: 2020-06-10
|
||||
- Comments: 3
|
||||
- Problem: RTMP cannot play in HTML5 mode after Flash deprecation.
|
||||
- Notes: comment says RTMP only works with Flash; another suggests FLV.js.
|
||||
- Follow-up: document RTMP limitation clearly; avoid promising HTML5 RTMP support unless using another playback strategy.
|
||||
- Code status: documented limitation. RTMP H5 support is not fixed in wrapper.
|
||||
|
||||
### #21 直播,不能播放flv格式的视频
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/21
|
||||
- Created: 2020-08-10
|
||||
- Comments: 1
|
||||
- Problem: FLV live stream fails both by `source` and dynamic `loadByUrl`.
|
||||
- Notes: maintainer suggested validating stream in VLC and checking Aliplayer config.
|
||||
- Follow-up: create verified FLV live test case and document required options.
|
||||
- Code status: improved. Wrapper infers `format: 'flv'`; `lowLatency` adds FLV live buffer defaults. Needs real FLV source validation.
|
||||
|
||||
### #24 mp4格式视频加载错误4400
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/24
|
||||
- Created: 2020-09-27
|
||||
- Comments: 4
|
||||
- Problem: large or special MP4 URL reports error 4400; user says autoplay is false but play still appears to trigger.
|
||||
- Notes: maintainer suspected URL permissions/cross-origin/path encoding; reporter later said the URL contains Chinese characters.
|
||||
- Follow-up: test encoded vs unencoded URLs, autoplay false behavior, and error handling for cross-origin/private MP4.
|
||||
- Code status: improved. Wrapper now `encodeURI`s source URLs by default to handle Chinese filenames. Cross-origin/private URL failures remain source/server issues.
|
||||
|
||||
### #37 发现m3u8视频播放时的问题
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/37
|
||||
- Created: 2021-01-07
|
||||
- Comments: 1
|
||||
- Problem: M3U8 quality switching is delayed; after switching and refreshing, playback fails.
|
||||
- Follow-up: reproduce with multi-quality M3U8 source and inspect whether wrapper re-init/load flow loses format or quality state.
|
||||
- Code status: improved. Wrapper infers source format and rebuilds player on cross-format changes instead of always calling `loadByUrl`.
|
||||
|
||||
### #52 flv直播刷新页面视频卡住
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/52
|
||||
- Created: 2021-06-16
|
||||
- Comments: 3
|
||||
- Problem: FLV live video gets stuck after page refresh.
|
||||
- Notes: reporter confirmed issue was still unresolved in 2021.
|
||||
- Follow-up: include in FLV live repro matrix with #21 and #68.
|
||||
- Code status: improved by FLV format inference, async init guards, and `lowLatency`; still needs real stream repro.
|
||||
|
||||
### #68 播放Flv视频直播时,时间长了后会延迟几分钟
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/68
|
||||
- Created: 2022-12-17
|
||||
- Comments: 0
|
||||
- Problem: FLV live stream accumulates several minutes of latency over time.
|
||||
- Follow-up: check Aliplayer FLV buffer options such as stash buffer settings and live latency handling.
|
||||
- Code status: improved. `lowLatency` applies `enableStashBufferForFlv: false` and `stashInitialSizeForFlv: 128` unless explicitly overridden.
|
||||
|
||||
## Playback APIs And Source Modes
|
||||
|
||||
### #43 vid+palyauth播放问题
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/43
|
||||
- Created: 2021-03-06
|
||||
- Comments: 5
|
||||
- Problem: `replayByVidAndPlayAuth` appears undefined from both `getPlayer()` and component ref.
|
||||
- Notes: later comment says methods like `replay()` and `pause()` were also undefined; maintainer notes multiple refs become arrays; user later resolved.
|
||||
- Follow-up: improve docs for `$refs` in single vs multiple-player usage and when methods are available.
|
||||
- Code status: fixed for Vue 3 docs. README now shows typed `ref<VueAliplayerV2Expose | null>`.
|
||||
|
||||
### #49 这个不支持vid+playauth播放吗
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/49
|
||||
- Created: 2021-05-18
|
||||
- Comments: 3
|
||||
- Problem: question about `vid + playauth` playback support.
|
||||
- Notes: comment says it works when adding `encryptType: 1`; later user asks what else is required.
|
||||
- Follow-up: add working `vid + playauth` example and option notes.
|
||||
- Code status: documented. `vid + playauth` is supported through `options`; ref method remains exposed.
|
||||
|
||||
## UI, Skin, And Extension Features
|
||||
|
||||
### #53 播放按钮
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/53
|
||||
- Created: 2021-06-21
|
||||
- Comments: 14
|
||||
- Problem: users ask how to center play button, configure quality/subtitle options, change cover, and adjust progress/button colors.
|
||||
- Notes: maintainer answered that `skinLayout` must be placed inside `options`; example uses `skinLayout: [{ name: 'bigPlayButton', align: 'cc' }]`.
|
||||
- Follow-up: add skin customization examples to README.
|
||||
- Code status: partially documented through options passthrough. More visual skin examples can be added later.
|
||||
|
||||
### #55 请问我要把清晰度切换单独放到设置外面要怎么弄呢?
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/55
|
||||
- Created: 2021-06-22
|
||||
- Comments: 1
|
||||
- Problem: user wants quality switch outside the settings menu.
|
||||
- Notes: maintainer pointed to Aliplayer skin settings docs.
|
||||
- Follow-up: document whether this is possible through `skinLayout` or requires custom components.
|
||||
- Code status: documented as Aliplayer skin/custom component responsibility.
|
||||
|
||||
### #57 自定义组件
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/57
|
||||
- Created: 2021-07-06
|
||||
- Comments: 4
|
||||
- Problem: user asks whether Aliplayer custom component API is supported for a playlist.
|
||||
- Notes: maintainer says SDK should support it, but another user says adding `components` in `options` does not work unless custom component JS is separately loaded.
|
||||
- Follow-up: verify custom component loading order and provide an example if supported.
|
||||
- Code status: improved. Added `componentScripts` to load custom component scripts before player init; README includes example.
|
||||
|
||||
### #61 播放失败页面自定义
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/61
|
||||
- Created: 2021-09-24
|
||||
- Comments: 1
|
||||
- Problem: clicking refresh on the player error page refreshes the whole page; user wants local refresh or custom refresh handler.
|
||||
- Notes: maintainer says the error page comes from Aliplayer.
|
||||
- Follow-up: check whether SDK exposes error UI customization or whether wrapper can expose a local retry pattern.
|
||||
- Code status: improved. Added `reload()` / `retry()` exposed methods for local retry; SDK error UI itself remains upstream.
|
||||
|
||||
### #67 跑马灯功能可以用吗
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/67
|
||||
- Created: 2022-10-08
|
||||
- Comments: 0
|
||||
- Problem: user asks whether marquee/watermark scrolling text is available.
|
||||
- Follow-up: verify Aliplayer support and document unsupported/supported approach.
|
||||
- Code status: documented via `componentScripts` + `options.components`; availability depends on the loaded Aliplayer custom component.
|
||||
|
||||
### #59 如何关闭track
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/59
|
||||
- Created: 2021-08-20
|
||||
- Comments: 1
|
||||
- Problem: player sends tracking POST requests to `https://videocloud.cn-hangzhou.log.aliyuncs.com/logstores/newplayer/track`; user wants to disable.
|
||||
- Notes: a comment suggests deleting `postWithHeader`, which is not a clean wrapper-level solution.
|
||||
- Follow-up: find official SDK option, if any; otherwise document limitation.
|
||||
- Code status: opt-in mitigation added. `disableTracking` can block known Aliplayer tracking URLs at wrapper level.
|
||||
|
||||
## Format And Capability Questions
|
||||
|
||||
### #60 能播vr视频或者vr直播吗
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/60
|
||||
- Created: 2021-09-16
|
||||
- Comments: 1
|
||||
- Problem: asks whether VR video or VR live can be played.
|
||||
- Notes: maintainer had not tested.
|
||||
- Follow-up: verify upstream Aliplayer capability and document scope.
|
||||
- Code status: documentation-only. Wrapper passes options through but does not implement VR rendering itself.
|
||||
|
||||
### #66 支持AVI 格式的视频吗?
|
||||
|
||||
- Link: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/66
|
||||
- Created: 2022-09-07
|
||||
- Comments: 0
|
||||
- Problem: asks whether AVI format is supported.
|
||||
- Follow-up: document supported formats according to upstream Aliplayer/browser support.
|
||||
- Code status: documented format scope. AVI is not claimed as supported by this wrapper.
|
||||
708
README.md
708
README.md
@ -1,512 +1,296 @@
|
||||
# vue-alipayer-v2
|
||||
# vue-aliplayer-v2
|
||||
|
||||
## 感谢每一位支持开源的朋友. 这是一个基于 Alipayer 开发并封装成 vue 组件的播放器.
|
||||
基于阿里云 Aliplayer SDK 的 Vue 3 播放器组件。可通过 Aliplayer 官方能力播放 mp4、m3u8、flv、直播流、加密点播、清晰度切换和直播时移等场景。
|
||||
|
||||
### vue 中使用 Alipayer,播放 rtmp,m3u8,mp4 视频
|
||||
> v2 从 Vue 3 + Vite 重构开始,不再兼容 Vue 2。Vue 2 项目请继续安装 `vue-aliplayer-v2@1.x`。
|
||||
|
||||
#### [本项目在线演示](https://langyuxiansheng.github.io/vue-aliplayer-v2/)
|
||||
## 在线演示
|
||||
|
||||
#### [阿里云播放器在线演示](https://player.alicdn.com/aliplayer/index.html)
|
||||
- 项目演示:https://langyuxiansheng.github.io/vue-aliplayer-v2/
|
||||
- 阿里云播放器演示:https://player.alicdn.com/aliplayer/index.html
|
||||
|
||||
> 假如此轮子对你有帮助,请顺手 star 一下吧.o(_ ̄︶ ̄_)o
|
||||
|
||||
## 1.安装使用! 下载安装 npm 包
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
npm i vue-aliplayer-v2
|
||||
```
|
||||
|
||||
```bash
|
||||
npm i vue-aliplayer-v2 --save
|
||||
or
|
||||
yarn add vue-aliplayer-v2
|
||||
```
|
||||
|
||||
#### 全局注册 main.js
|
||||
## 全局注册
|
||||
|
||||
```javascript
|
||||
import VueAliplayerV2 from "vue-aliplayer-v2";
|
||||
```ts
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import VueAliplayerV2 from 'vue-aliplayer-v2';
|
||||
|
||||
Vue.use(VueAliplayerV2);
|
||||
const app = createApp(App);
|
||||
|
||||
//可选全局配置
|
||||
//Vue.use(VueAliplayerV2,{
|
||||
// cssLink: 'https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css',
|
||||
// scriptSrc: 'https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js'
|
||||
//});
|
||||
app.use(VueAliplayerV2, {
|
||||
// 默认使用阿里云 Web 播放器 SDK 2.37.0,新版 SDK 走 imp-web-player 资源路径
|
||||
sdkVersion: '2.37.0',
|
||||
// 可选:覆盖完整 SDK 地址
|
||||
cssLink: 'https://g.alicdn.com/apsara-media-box/imp-web-player/2.37.0/skins/default/aliplayer-min.css',
|
||||
scriptSrc: 'https://g.alicdn.com/apsara-media-box/imp-web-player/2.37.0/aliplayer-min.js'
|
||||
});
|
||||
|
||||
app.mount('#app');
|
||||
```
|
||||
|
||||
#### 局部注册 App.vue
|
||||
## 局部注册
|
||||
|
||||
```javascript
|
||||
//推荐第一种(仅v1.2.3)及以上的版本可用
|
||||
import VueAliplayerV2 from "vue-aliplayer-v2";
|
||||
components: {
|
||||
VueAliplayerV2;
|
||||
}
|
||||
|
||||
//或者
|
||||
components: {
|
||||
VueAliplayerV2: VueAliplayerV2.Player;
|
||||
}
|
||||
```
|
||||
|
||||
## 2.组件中使用
|
||||
|
||||
### 组件模板使用,下面的视频连接仅供演示测试.
|
||||
|
||||
```html
|
||||
```vue
|
||||
<template>
|
||||
<div id="app">
|
||||
<template v-if="!isShowMultiple && show">
|
||||
<vue-aliplayer-v2
|
||||
<VueAliplayerV2
|
||||
ref="playerRef"
|
||||
:source="source"
|
||||
ref="VueAliplayerV2"
|
||||
:options="options"
|
||||
/>
|
||||
</template>
|
||||
<div v-if="isShowMultiple && show" class="show-multiple">
|
||||
<template v-for="x in 5">
|
||||
<vue-aliplayer-v2
|
||||
class="multiple-player"
|
||||
:key="x"
|
||||
:source="source"
|
||||
ref="VueAliplayerV2"
|
||||
:options="options"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<p class="remove-text" v-if="!show">播放器已销毁!</p>
|
||||
<div class="player-btns">
|
||||
<template v-if="!isShowMultiple && show">
|
||||
<span @click="play()">播放</span>
|
||||
<span @click="pause()">暂停</span>
|
||||
<span @click="replay()">重播</span>
|
||||
<span @click="getCurrentTime()">播放时刻</span>
|
||||
<span @click="getStatus()">获取播放器状态</span>
|
||||
</template>
|
||||
<span @click="show = !show">{{ show ? '销毁' : '重载' }}</span>
|
||||
<span @click="options.isLive = !options.isLive"
|
||||
>{{ options.isLive ? '切换普通模式' : '切换直播模式' }}</span
|
||||
>
|
||||
<span @click="showMultiple()"
|
||||
>{{isShowMultiple ? '显示1个播放器' : '显示多个播放器'}}</span
|
||||
>
|
||||
</div>
|
||||
<div class="source-box">
|
||||
<span class="source-label">选择播放源(支持动态切换):</span>
|
||||
<select v-model="source" name="source" id="source">
|
||||
<option value="//player.alicdn.com/video/aliyunmedia.mp4"
|
||||
>播放源1</option
|
||||
>
|
||||
<option value="//yunqivedio.alicdn.com/user-upload/nXPDX8AASx.mp4"
|
||||
>播放源2</option
|
||||
>
|
||||
<option
|
||||
value="//tbm-auth.alicdn.com/e7qHgLdugbzzKh2eW0J/kXTgBkjvNXcERYxh2PA@@hd_hq.mp4?auth_key=1584519814-0-0-fc98b2738f331ff015f7bf5c62394888"
|
||||
>播放源3</option
|
||||
>
|
||||
<option value="//ivi.bupt.edu.cn/hls/cctv1.m3u8">直播播放源4</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="source-box">
|
||||
<span class="source-label">输入播放源(支持动态切换):</span>
|
||||
<input class="source-input" type="text" v-model="source" />
|
||||
</div>
|
||||
</div>
|
||||
:license="license"
|
||||
low-latency
|
||||
@ready="handleReady"
|
||||
@error="handleError"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
// source:'//player.alicdn.com/video/aliyunmedia.mp4',
|
||||
isLive: true, //切换为直播流的时候必填
|
||||
// format: 'm3u8' //切换为直播流的时候必填
|
||||
},
|
||||
source: "//player.alicdn.com/video/aliyunmedia.mp4",
|
||||
// source: '//ivi.bupt.edu.cn/hls/cctv1.m3u8',
|
||||
show: true,
|
||||
isShowMultiple: false,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
play() {
|
||||
this.$refs.VueAliplayerV2.play();
|
||||
},
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import VueAliplayerV2, {
|
||||
type AliplayerLicense,
|
||||
type AliplayerOptions,
|
||||
type VueAliplayerV2Expose
|
||||
} from 'vue-aliplayer-v2';
|
||||
|
||||
pause() {
|
||||
this.$refs.VueAliplayerV2.pause();
|
||||
},
|
||||
const playerRef = ref<VueAliplayerV2Expose | null>(null);
|
||||
const source = ref('//player.alicdn.com/video/aliyunmedia.mp4');
|
||||
const license = ref<AliplayerLicense | null>(null);
|
||||
const options = reactive<AliplayerOptions>({
|
||||
autoplay: true,
|
||||
isLive: false,
|
||||
useH5Prism: true
|
||||
});
|
||||
|
||||
replay() {
|
||||
this.$refs.VueAliplayerV2.replay();
|
||||
},
|
||||
function handleReady() {
|
||||
playerRef.value?.play();
|
||||
}
|
||||
|
||||
getCurrentTime() {
|
||||
// this.$refs.VueAliplayerV2.getCurrentTime();
|
||||
this.source = "http://ivi.bupt.edu.cn/hls/cctv1.m3u8";
|
||||
},
|
||||
|
||||
getStatus() {
|
||||
const status = this.$refs.VueAliplayerV2.getStatus();
|
||||
console.log(`getStatus:`, status);
|
||||
alert(`getStatus:${status}`);
|
||||
},
|
||||
|
||||
showMultiple() {
|
||||
this.isShowMultiple = !this.isShowMultiple;
|
||||
},
|
||||
},
|
||||
};
|
||||
function handleError(error: unknown) {
|
||||
console.log('player error', error);
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.remove-text {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
font-size: 24px;
|
||||
}
|
||||
.show-multiple {
|
||||
display: flex;
|
||||
.multiple-player {
|
||||
width: calc(100% / 4);
|
||||
margin: 20px;
|
||||
}
|
||||
}
|
||||
.player-btns {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
span {
|
||||
margin: 0 auto;
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
border: 1px solid #eee;
|
||||
background: #e1e1e1;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.source-box {
|
||||
padding: 5px 10px;
|
||||
margin-bottom: 20px;
|
||||
.source-label {
|
||||
margin-right: 20px;
|
||||
font-size: 16px;
|
||||
display: block;
|
||||
}
|
||||
#source {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.source-input {
|
||||
margin-top: 10px;
|
||||
padding: 5px 10px;
|
||||
width: 80%;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## 3.功能与配置
|
||||
## Props
|
||||
|
||||
```javascript
|
||||
props:{
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `source` | `string \| null` | `null` | 播放源。存在时优先于 `options.source`,变更后会调用底层 `loadByUrl` 动态切换。 |
|
||||
| `options` | `AliplayerOptions \| null` | `null` | 透传给 Aliplayer 的配置项。 |
|
||||
| `license` | `AliplayerLicense \| null` | `null` | Aliplayer License 配置,等价于 `options.license`,适配新版 SDK 要求。 |
|
||||
| `autoFormat` | `boolean` | `true` | 根据 `source` 后缀自动补充 `format`,支持 `mp4/m3u8/flv/mp3/rtmp`。 |
|
||||
| `lowLatency` | `boolean` | `false` | FLV 直播低延迟预设,会在 `isLive + flv` 时默认关闭 stash buffer。 |
|
||||
| `normalizeSourceUrl` | `boolean` | `true` | 自动对非 ASCII 播放地址执行 `encodeURI`,处理中文文件名等 URL。 |
|
||||
| `forbidFastForward` | `boolean` | `false` | 禁止拖拽快进。通过监听 `timeupdate` 回退到上次播放位置实现。 |
|
||||
| `sdkVersion` | `string` | `2.37.0` | 生成阿里云 `imp-web-player` SDK 资源地址。 |
|
||||
| `cssLink` | `string` | Aliplayer 2.37.0 CSS | 覆盖播放器样式地址。 |
|
||||
| `scriptSrc` | `string` | Aliplayer 2.37.0 JS | 覆盖播放器脚本地址。 |
|
||||
| `componentScripts` | `string[]` | `[]` | 额外加载自定义组件脚本,需在播放器初始化前加载。 |
|
||||
| `disableTracking` | `boolean` | `false` | 可选拦截 Aliplayer 已知 track 上报请求。 |
|
||||
| `trackingUrlPatterns` | `Array<string \| RegExp>` | `[]` | 自定义需要拦截的 track URL 片段或正则。 |
|
||||
|
||||
forbidFastForward: { //禁止拖拽快进
|
||||
required: false,
|
||||
type: [Boolean],
|
||||
default: false
|
||||
},
|
||||
|
||||
options: { //配置项 (options.source 不支持动态切换,需要动态切换请直接使用source)
|
||||
required: false,
|
||||
type: [Object],
|
||||
default: () => null
|
||||
},
|
||||
## Events
|
||||
|
||||
source: { //播放源(此属性存在则优先于options.source) 支持动态切换,目前只支持同种格式(mp4/flv/m3u8)之间切换。暂不支持直播rtmp流切换。
|
||||
required: false,
|
||||
type: [Object],
|
||||
default: () => null
|
||||
},
|
||||
组件会透传常用 Aliplayer 事件:
|
||||
|
||||
cssLink:{ //css版本源
|
||||
required: false,
|
||||
type: [String],
|
||||
default: `https://g.alicdn.com/de/prismplayer/2.9.7/skins/default/aliplayer-min.css`
|
||||
},
|
||||
scriptSrc:{ //js版本源
|
||||
required: false,
|
||||
type: [String],
|
||||
default: `https://g.alicdn.com/de/prismplayer/2.9.7/aliplayer-min.js`
|
||||
}
|
||||
```ts
|
||||
ready
|
||||
play
|
||||
pause
|
||||
canplay
|
||||
playing
|
||||
ended
|
||||
liveStreamStop
|
||||
onM3u8Retry
|
||||
hideBar
|
||||
showBar
|
||||
waiting
|
||||
timeupdate
|
||||
snapshoted
|
||||
requestFullScreen
|
||||
cancelFullScreen
|
||||
error
|
||||
startSeek
|
||||
completeSeek
|
||||
sdk-error
|
||||
```
|
||||
|
||||
`sdk-error` 是组件额外事件,在 Aliplayer SDK 脚本加载失败时触发。
|
||||
|
||||
## Ref 方法
|
||||
|
||||
```ts
|
||||
playerRef.value?.play();
|
||||
playerRef.value?.pause();
|
||||
playerRef.value?.replay();
|
||||
playerRef.value?.seek(30);
|
||||
playerRef.value?.getCurrentTime();
|
||||
playerRef.value?.getDuration();
|
||||
playerRef.value?.getVolume();
|
||||
playerRef.value?.setVolume(0.8);
|
||||
playerRef.value?.loadByUrl('//player.alicdn.com/video/aliyunmedia.mp4');
|
||||
playerRef.value?.getStatus();
|
||||
playerRef.value?.requestFullScreen();
|
||||
playerRef.value?.cancelFullScreen();
|
||||
playerRef.value?.dispose();
|
||||
playerRef.value?.getPlayer();
|
||||
```
|
||||
|
||||
完整暴露方法包括:
|
||||
|
||||
```ts
|
||||
getPlayer
|
||||
init
|
||||
initPlayer
|
||||
reload
|
||||
retry
|
||||
play
|
||||
pause
|
||||
replay
|
||||
seek
|
||||
getCurrentTime
|
||||
getDuration
|
||||
getVolume
|
||||
setVolume
|
||||
loadByUrl
|
||||
replayByVidAndPlayAuth
|
||||
replayByVidAndAuthInfo
|
||||
setPlayerSize
|
||||
setSpeed
|
||||
setSanpshotProperties
|
||||
requestFullScreen
|
||||
cancelFullScreen
|
||||
getIsFullScreen
|
||||
getStatus
|
||||
setLiveTimeRange
|
||||
setRotate
|
||||
getRotate
|
||||
setImage
|
||||
dispose
|
||||
setCover
|
||||
setProgressMarkers
|
||||
setPreviewTime
|
||||
getPreviewTime
|
||||
isPreview
|
||||
off
|
||||
```
|
||||
|
||||
## 多播放器
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<VueAliplayerV2
|
||||
v-for="item in sources"
|
||||
:key="item"
|
||||
:source="item"
|
||||
:options="options"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
v2 的 SDK 加载器会复用同一份 CSS/JS 资源,多个播放器同时挂载时不会重复插入相同的 SDK 标签。
|
||||
|
||||
## License
|
||||
|
||||
阿里云新版 Web 播放器 SDK 要求配置网站域名和 License Key。可以通过 `license` prop 或 `options.license` 传入:
|
||||
|
||||
```vue
|
||||
<VueAliplayerV2
|
||||
:source="source"
|
||||
:license="{ domain: 'example.com', key: 'example-key' }"
|
||||
/>
|
||||
```
|
||||
|
||||
## VID + PlayAuth
|
||||
|
||||
```vue
|
||||
<VueAliplayerV2
|
||||
:options="{
|
||||
vid: '<your video ID>',
|
||||
playauth: '<your PlayAuth>',
|
||||
authTimeout: 7200
|
||||
}"
|
||||
/>
|
||||
```
|
||||
|
||||
`vid + playauth` 是初始化配置,不需要再传 `source`。如果要在播放器创建后切换,可以调用:
|
||||
|
||||
```ts
|
||||
playerRef.value?.replayByVidAndPlayAuth(vid, playauth);
|
||||
```
|
||||
|
||||
## FLV/HLS/RTMP 说明
|
||||
|
||||
- FLV 直播请设置 `options.isLive = true`,组件会自动推断 `format: 'flv'`。
|
||||
- 开启 `low-latency` 后,FLV 直播默认使用 `enableStashBufferForFlv: false` 和 `stashInitialSizeForFlv: 128`,可在 `options` 中覆盖。
|
||||
- m3u8、flv、mp4 跨格式切换时,v2 会自动重建播放器;同格式切换优先调用 `loadByUrl`。
|
||||
- RTMP 在现代浏览器 H5 模式下不再可靠,建议服务端转 HLS/FLV/RTS。
|
||||
|
||||
## 自定义组件和跑马灯
|
||||
|
||||
Aliplayer 自定义组件需要额外加载组件脚本,然后通过 `options.components` 注入。组件提供 `componentScripts` 保证脚本在播放器初始化前加载:
|
||||
|
||||
```vue
|
||||
<VueAliplayerV2
|
||||
:source="source"
|
||||
:component-scripts="['/aliplayer-components/playlist.js']"
|
||||
:options="{
|
||||
components: [
|
||||
{
|
||||
name: 'PlaylistComponent',
|
||||
type: window.PlaylistComponent,
|
||||
args: { list: playlist }
|
||||
}
|
||||
]
|
||||
}"
|
||||
/>
|
||||
```
|
||||
|
||||
跑马灯、水印、播放列表等能力是否可用取决于所加载的 Aliplayer 自定义组件脚本。
|
||||
|
||||
## 失败重试
|
||||
|
||||
播放器错误页属于 Aliplayer SDK 内部 UI。业务侧可以监听 `error` 后使用组件暴露的 `retry()` 或 `reload()` 做局部重试:
|
||||
|
||||
```ts
|
||||
function handleError() {
|
||||
playerRef.value?.retry();
|
||||
}
|
||||
```
|
||||
|
||||
### 3.1 配置项 options 属性
|
||||
|
||||
可以参考 [属性和接口说明](https://help.aliyun.com/document_detail/125572.html?spm=a2c4g.11186623.6.1085.36fc6fc57WKZ5P)
|
||||
|
||||
| 名称 | 类型 | 说明 |
|
||||
| :----------------------- | :-----------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| source | String | 视频播放地址 url:单独 url。默认状态,表示使用 vid+playauth。source 播放方式优先级最高。source 支持多清晰度设置:source:’{“HD”:”address1”,”SD”:”address2”’,详情参见多清晰度播放。 |
|
||||
| vid | String | 媒体转码服务的媒体 Id。 |
|
||||
| playauth | String | 播放权证,如何得到参见获取 playauth。 |
|
||||
| height | String | 播放器高度,可形如‘100%’或者‘100px’,chrome 浏览器下 flash 播放器分别不能小于 397x297。 |
|
||||
| width | String | 播放器宽度,可形如‘100%’或者‘100px’,chrome 浏览器下 flash 播放器分别不能小于 397x297。 |
|
||||
| videoWidth | String | 视频宽度,仅 h5 支持。详情参见旋转和镜像。 |
|
||||
| videoHeight | String | 视频高度,仅 h5 支持。详情参见旋转和镜像。 |
|
||||
| preload | Boolean | 播放器自动加载,目前仅 h5 可用。 |
|
||||
| cover | String | 播放器默认封面图片,请填写正确的图片 url 地址。需要 autoplay 为’false’时,才生效。Flash 播放器封面也需要开启允许跨域访问。 |
|
||||
| isLive | Boolean | 播放内容是否为直播,直播时会禁止用户拖动进度条。 |
|
||||
| autoplay | Boolean | 播放器是否自动播放,在移动端 autoplay 属性会失效。Safari11 不会自动开启自动播放如何开启。 |
|
||||
| rePlay | Boolean | 播放器自动循环播放。 |
|
||||
| useH5Prism | Boolean | 指定使用 H5 播放器。 |
|
||||
| useFlashPrism | Boolean | 指定使用 Flash 播放器。 |
|
||||
| playsinline | Boolean | H5 是否内置播放,有的 Android 浏览器不起作用。 |
|
||||
| showBuffer | Boolean | 显示播放时缓冲图标,默认 true。 |
|
||||
| skinRes | Url | 说明:皮肤图片,不建议随意修改该字段,如要修改,请参照皮肤定制。 |
|
||||
| skinLayout | Array Boolean | 说明:功能组件布局配置,不传该字段使用默认布局。传 false 隐藏所有功能组件,请参照皮肤定制。 |
|
||||
| controlBarVisibility | String | 控制面板的实现,默认为‘hover’。可选的值为:‘click’、‘hover’、‘always’。 |
|
||||
| showBarTime | String | 控制栏自动隐藏时间(ms)。 |
|
||||
| extraInfo | String | 说明:JSON 串用于定制性接口参数。 |
|
||||
| > | > | 1.“fullTitle”:“测试页面”全屏时显示视频标题(仅 flash 支持)。 |
|
||||
| > | > | 2. “m3u8BufferLength”:“30”播放 m3u8 时加载缓存 ts 文件长度单位(秒)(仅 flash 支持)。 |
|
||||
| > | > | 3. “liveStartTime”:“2016/08/17 12:00:00”,直播开始时间,用于提示直播未开始(仅 flash 支持)。 |
|
||||
| > | > | 4. “liveOverTime”:“2016/08/17 14:00:00”,直播结束时间,用于提示直播结束(仅 flash 支持)。 |
|
||||
| enableSystemMenu | Boolean | 是否允许系统右键菜单显示,默认为 false。 |
|
||||
| format | String | 指定播放地址格式,只有使用 vid 的播放方式时支持,可选值为’mp4’、’m3u8’、’flv’、’mp3’,默认为空,仅 H5 支持。 |
|
||||
| mediaType | String | 指定返回音频还是视频,只有使用 vid 的播放方式时支持。可选值为’video’和’audio’,默认为’video’,‘audio’主要是针对只包含音频的视频格式,比如音频的 mp4,仅 H5 支持。 |
|
||||
| qualitySort | String | 指定排序方式,只有使用 vid + plauth 播放方式时支持。‘desc’表示按倒序排序(即:从大到小排序),‘asc’表示按正序排序(即:从小到大排序),默认值:‘asc’,仅 H5 支持。 |
|
||||
| definition | String | 显示视频清晰度,多个用逗号分隔,比如:’FD,LD’,此值是 vid 对应流清晰度的一个子集,取值范围:FD(流畅)LD(标清)SD(高清)HD(超清)OD(原画)2K(2K)4K(4K),仅 H5 支持。 |
|
||||
| defaultDefinition | String | 默认视频清晰度,此值是 vid 对应流的一个清晰度,取值范围:FD(流畅)LD(标清)SD(高清)HD(超清)OD(原画)2K(2K)4K(4K),仅 H5 支持。 |
|
||||
| x5_type | String | 声明启用同层 H5 播放器,启用时设置的值为‘h5’,详情参见同层播放。 |
|
||||
| x5_fullscreen | Boolean | 声明视频播放时是否进入到 TBS 的全屏模式,默认为 false。当需要把视频做为背景时,设置为 true,详情参见同层播放。 |
|
||||
| x5_video_position | String | 声明视频播在界面上的位置,默认为“center”。可选值为:“top”,“center”,详情参见同层播放。 |
|
||||
| x5_orientation | String | 声明 TBS 播放器支持的方向,可选值:landscape:横屏,portraint:竖屏,详情参见同层播放。 |
|
||||
| x5LandscapeAsFullScreen | String | 声明 TBS 全屏播放是否横屏,默认值为 true。 |
|
||||
| autoPlayDelay | Number | 延迟播放时间,单位为秒。详情参见延迟播放 |
|
||||
| autoPlayDelayDisplayText | String | 延迟播放提示文本,详情参见延迟播放。 |
|
||||
| language | String | 国际化,默认为‘zh-cn’。如果未设置,则采用浏览器语言。可选值为‘zh-cn’、‘en-us’或其它值。 |
|
||||
| languageTexts | JSON | 自定义国际化文本 json 结构,key 的值需要和 language 属性值对应起来。例子:{jp:{Play:”Play”}},自定义值参见 Json 结构。 |
|
||||
| snapshot | Boolean | flash 启用截图功能。 |
|
||||
| snapshotWatermark | Object | H5 设置截图水印。 |
|
||||
| useHlsPluginForSafari | Boolean | Safari 浏览器可以启用 Hls 插件播放,Safari 11 除外。 |
|
||||
| enableStashBufferForFlv | Boolean | H5 播放 flv 时,设置是否启用播放缓存,只在直播下起作用。 |
|
||||
| stashInitialSizeForFlv | Number | H5 播放 flv 时,初始缓存大小,只在直播下起作用。 |
|
||||
| loadDataTimeout | Number | 缓冲多长时间后,提示用户切换低清晰度,默认:20 秒。 |
|
||||
| waitingTimeout | Number | 最大缓冲超时时间,超过这个时间会有错误提示,默认:60 秒。 |
|
||||
| liveStartTime | String | 直播开始时间,直播时移功能使用,格式为:“2018/01/04 12:00:00”。 |
|
||||
| liveOverTime | String | 直播结束时间,直播时移功能使用,格式为:“2018/01/04 12:00:00”。 |
|
||||
| liveTimeShiftUrl | String | 直播可用时移查询地址,详情参见直播时移。 |
|
||||
| liveShiftSource | String | flv 直播地址播放时,hls 的流地址,详情参见直播时移。 |
|
||||
| recreatePlayer | Function | flv 直播和 hls 时移切换是,重新创建播放器方法,详情参见直播时移。 |
|
||||
| diagnosisButtonVisible | Boolean | 是否显示检测按钮,默认为 true。 |
|
||||
| disableSeek | Boolean | 禁用进度条的 Seek,默认为 false,仅 Flash 支持。 |
|
||||
| encryptType | int | 加密类型,播放点播私有加密视频时,设置值为 1,默认值为 0。 |
|
||||
| progressMarkers | Array | 进度条打点内容数组,详情参见进度条打点。 |
|
||||
| vodRetry | int | 点播失败重试次数,默认 3 次 |
|
||||
| liveRetry | int | 直播播放失败重试次数,默认 5 次 |
|
||||
|
||||
### 3.2 播放器方法
|
||||
|
||||
```javascript
|
||||
// 暂停播放
|
||||
this.$refs.VueAliplayerV2.pause();
|
||||
```
|
||||
|
||||
可以参考 [播放器接口方法](https://help.aliyun.com/document_detail/125572.html?spm=a2c4g.11186623.6.1085.36fc6fc57WKZ5P#h2-u64ADu653Eu5668u63A5u53E32)
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| :--------------------- | :------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| play | - | 播放视频。 |
|
||||
| pause | - | 暂停视频。 |
|
||||
| replay | - | 重播视频。 |
|
||||
| seek | time | 跳转到某个时刻进行播放,time 的单位为秒。 |
|
||||
| getCurrentTime | - | 获取当前的播放时刻,返回的单位为秒。 |
|
||||
| getDuration | - | 获取视频总时长,返回的单位为秒,这个需要在视频加载完成以后才可以获取到,可以在 play 事件后获取。 |
|
||||
| getVolume | - | 获取当前的音量,返回值为 0-1 的实数。ios 和部分 android 会失效。 |
|
||||
| setVolume | - | 设置音量,vol 为 0-1 的实数,ios 和部分 android 会失效。 |
|
||||
| loadByUrl | url,time | 直接播放视频 url,time 为可选值(单位秒)。目前只支持同种格式(mp4/flv/m3u8)之间切换。暂不支持直播 rtmp 流切换。 |
|
||||
| replayByVidAndPlayAuth | vid:视频 id,playauth:播放凭证 | 目前只支持 H5 播放器。暂不支持不同格式视频间的之间切换。暂不支持直播 rtmp 流切换。 |
|
||||
| replayByVidAndAuthInfo | 仅 MPS 用户时使用,参数顺序为:vid、accId、accSecret、stsToken、authInfo、domainRegion | 目前只支持 H5 播放器。暂不支持不同格式视频间的之间切换。暂不支持直播 rtmp 流切换。 |
|
||||
| setPlayerSize | w,h | 设置播放器大小 w,h 可分别为 400px 像素或 60%百分比。chrome 浏览器下 flash 播放器分别不能小于 397x297。 |
|
||||
| setSpeed | speed | 手动设置播放的倍速,倍速播放仅 H5 支持。移动端可能会失效,比如 android 微信。倍速播放 UI 默认是开启的。如果自定义过 skinLaout 属性,需要添加 speedButton 项到数组里: |
|
||||
| > | > | {name:“speedButton”,align:“tr”,x:10,y:23} |
|
||||
| setSanpshotProperties | width:宽度,height:高度,rate:截图质量 | 设置截图参数。 |
|
||||
| requestFullScreen | - | 播放器全屏,仅 H5 支持。 |
|
||||
| cancelFullScreen | - | 播放器退出全屏,iOS 调用无效,仅 H5 支持。 |
|
||||
| getIsFullScreen | - | 获取播放器全屏状态,仅 H5 支持。 |
|
||||
| getStatus | - | 获取播放器状态,包含的值:‘init’,‘ready’,‘loading’,‘play’,‘pause’,‘playing’,‘waiting’,‘error’,‘ended’ |
|
||||
| setLiveTimeRange | 开始时间,结束时间 | 设置直播的开始结束时间,开启直播时移功能时使用。例子:player.liveShiftSerivce.setLiveTimeRange(“”,‘2018/01/04 20:00:00’) |
|
||||
| setRotate | rotate 旋转角度 | 参数为旋转角度, 正数为正时针旋转, 负数为逆时针旋转。例如: setRotate(90)。详情参见旋转和镜像。 |
|
||||
| getRotate | - | 获取旋转角度。详情参见旋转和镜像。 |
|
||||
| setImage | image:镜像类型,可选值为:horizon,vertical | 设置镜像,例如: setImage(‘horizon’)。详情参见旋转和镜像。 |
|
||||
| dispose | - | 播放器销毁 |
|
||||
| setCover | cover 封面地址 | 设置封面 |
|
||||
| setProgressMarkers | markers 打点数据集合 | 设置打点数据 |
|
||||
| setPreviewTime | time 试看时间 | 设置试看时间,单位为秒,详情参见试看 |
|
||||
| getPreviewTime | - | 获取试看时间 |
|
||||
| isPreview | - | 是否试看 |
|
||||
| off | ev:事件名[String],handle,事件回调方法[Function] | 通过播放器实例的 off 方法取消绑定的方法 |
|
||||
|
||||
## 4.播放器事件
|
||||
|
||||
```html
|
||||
<template>
|
||||
<vue-aliplayer-v2 @ready="handleReady" />
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
/**
|
||||
* 播放器事件回调
|
||||
*/
|
||||
handleReady(e) {
|
||||
console.log(`ready`, e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
可以参考 [播放器事件](https://help.aliyun.com/document_detail/125572.html?spm=a2c4g.11186623.6.1085.36fc6fc57WKZ5P#h2-u64ADu653Eu5668u4E8Bu4EF63)
|
||||
|
||||
| 名称 | 说明 |
|
||||
| :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ready | 播放器视频初始化按钮渲染完毕。播放器 UI 初始设置需要此事件后触发,避免 UI 被初始化所覆盖。播放器提供的方法需要在此事件发生后才可以调用。 |
|
||||
| play | 视频由暂停恢复为播放时触发。 |
|
||||
| pause | 视频暂停时触发。 |
|
||||
| canplay | 能够开始播放音频/视频时发生,会多次触发,仅 H5 播放器。 |
|
||||
| playing | 播放中,会触发多次。 |
|
||||
| ended | 当前视频播放完毕时触发。 |
|
||||
| liveStreamStop | 直播流中断时触发。m3u8/flv/rtmp 在重试 5 次未成功后触发。提示上层流中断或需要重新加载视频。PS:m3u8 一直自动重试,不需要上层添加重试。 |
|
||||
| onM3u8Retry | m3u8 直播流中断后重试事件,每次断流只触发一次。 |
|
||||
| hideBar | 控制栏自动隐藏事件。 |
|
||||
| showBar | 控制栏自动显示事件。 |
|
||||
| waiting | 数据缓冲事件。 |
|
||||
| timeupdate | 播放位置发生改变时触发,仅 H5 播放器。可通过 getCurrentTime 方法,得到当前播放时间。 |
|
||||
| snapshoted | 截图完成事件。 |
|
||||
| requestFullScreen | 全屏事件,仅 H5 支持。 |
|
||||
| cancelFullScreen | 取消全屏事件,iOS 下不会触发,仅 H5 支持。 |
|
||||
| error | 错误事件。 |
|
||||
| startSeek | 开始拖拽,参数返回拖拽点的时间。 |
|
||||
| completeSeek | 完成拖拽,参数返回拖拽点的时间。 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 图片展示
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
## 6.二次开发 下载项目
|
||||
## 开发
|
||||
|
||||
```bash
|
||||
git clone https://github.com/langyuxiansheng/vue-aliplayer-v2.git
|
||||
```
|
||||
|
||||
## Project setup
|
||||
|
||||
```bash
|
||||
cd vue-aliplayer-v2
|
||||
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
构建 demo:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
构建组件库:
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run type-check
|
||||
npm run lib
|
||||
```
|
||||
|
||||
## 7.缺陷 & 后期计划
|
||||
## 迁移说明
|
||||
|
||||
> 2019 年 12 月 27 日 更新优化局部引用方式
|
||||
|
||||
> 您有功能建议,或者 bug 反馈请留言.
|
||||
|
||||
## 8.感谢
|
||||
|
||||
---
|
||||
|
||||
- vue-aliplayer 的作者,项目地址:https://github.com/slacrey/vue-aliplayer
|
||||
|
||||
- Alipayer 阿里云的开源播放器 https://help.aliyun.com/document_detail/125572.html?spm=a2c4g.11186623.6.1085.36fc6fc57WKZ5P#h2-u64ADu653Eu5668u4E8Bu4EF63
|
||||
|
||||
### Customize configuration
|
||||
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
|
||||
## 更新日志
|
||||
|
||||
> v1.3.0 修复部分已知bug,增加forbidFastForward 属性,感谢 "william-xue"网友的功能提交.
|
||||
|
||||
- sdk 版本更新,默认 SDK 版本由 2.9.3 更新为 2.9.20
|
||||
- 默认注释更新
|
||||
- 增加禁止用户拖拽快进的属性选项 forbidFastForward [Boolean] 默认 false
|
||||
|
||||
> v1.2.9 修正部分默认属性, 感谢"Schean17"网友的反馈与建议.
|
||||
|
||||
> v1.2.8 更换底层默认 sdk 版本为 2.9.3 修复 options 遇到 update loop 错误 感谢"litmonw"网友的反馈与建议.
|
||||
|
||||
> v1.2.7 更换底层默认 sdk 版本为 2.9.1 的版本. 更新线上演示 demo 的选项
|
||||
|
||||
> v1.2.6 优化 beforeDestroy() 部分的代码.
|
||||
|
||||
> v1.2.5 更换默认的播放器 SDK 版本 2.8.2 => 2.9.0,2.8.2 的版本存在多个播放器同时播放直播流异常的 bug,增加了全局 SDK 版本配置,可以在 Vue.use()的时候进行配置.
|
||||
|
||||
> v1.2.4 修复多个播放器加载,只初始化一个播放器的 bug.文档部分更新,增加了问题栏. 感谢"沙洲 ad"的反馈与建议.
|
||||
|
||||
> v1.2.3 优化播放器的初始化代码,调整包内结构,优化局部组件的注册方式,也兼容老版本的引用方式.文档部分更新,增加了问题栏. 感谢"liangzhiyuan2015"和"fancheur"两位网友的反馈与建议.
|
||||
|
||||
> v1.2.2 修复指定 id 情况下,播放器报错"没有为播放器指定容器",目前移除外部指定 id 的方式,所有的播放器 id 都由内部生成,不再由外部指定容器(外部指定的意义并不大),其它的说明:更新 1.2.1 后报错 Uncaught TypeError: 没有为播放器指定容器,因为源码中变更了部分代码,以及最大限度的简化代码,组件内部的根容器就只有一个 div 容器,导致以前外部指定 id 的时候,容器 id 与外部的不一致,导致抛出异常了,现在已经紧急修复了,若在使用,请更新到 v1.2.2 的版本;如果使用了外部指定 id 的方式请移除外部的 id.否则 id 会出现重复的情况., 感谢"liyoro"的反馈和建议.
|
||||
|
||||
> v1.2.1 修复直播播放的情况下,播放器已经销毁,而后台还在继续下载资源造成卡顿的 bug,修复多个播放器只渲染 1 个的 bug, 感谢"Jonauil"和"guangming95"两位网友的反馈和建议.
|
||||
|
||||
> v1.2.0 修复播放源(MP4/m3u8)之间切换无法正常播放的 bug,增加 options 配置项动态响应功能,优化部分播放器的逻辑, 感谢"liyoro"网友的反馈和建议.
|
||||
|
||||
> v1.1.9 修复播放源(修复 prop:source 类型验证报错), 感谢"hugo2017"和“nullF”网友的反馈.
|
||||
|
||||
> v1.1.8 修复播放源(增加 source 属性类型错误),修复获取播放器状态 getStatus()方法报错, 感谢"kongjigu"网友的反馈.
|
||||
|
||||
> v1.1.7 增加动态切换播放源(增加 source 属性)功能 感谢"wikimo"和"jieruian"两位网友的反馈建议.
|
||||
|
||||
> v1.1.6 修复部分已知 bug 和优化局部的引用方式
|
||||
|
||||
---
|
||||
|
||||
## 其它问题
|
||||
|
||||
1. IOS 或者其它设备无法全屏播放,或者点击全屏按钮的时候也只是显示竖屏?
|
||||
|
||||
> 方案与问题所在:
|
||||
|
||||
一般情况下可能是开启了强制竖屏(也就是屏幕锁定)打开后就会竖屏而不会全屏了!如下关闭就可以了:
|
||||
参考 issues: https://github.com/langyuxiansheng/vue-aliplayer-v2/issues/25
|
||||
|
||||
-开启了屏幕锁定,只要上拉控制中心,点击屏幕锁定关闭就可以了!
|
||||
|
||||
-也可能是播放器或者浏览器兼容性问题.
|
||||
- v2 仅支持 Vue 3。
|
||||
- 入口从 Vue 2 插件模式迁移为 Vue 3 `app.use(...)`。
|
||||
- 组件 ref 需要通过 `ref<VueAliplayerV2Expose | null>` 使用。
|
||||
- 旧版本用户请安装 `vue-aliplayer-v2@1.x`。
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
}
|
||||
1
dist/assets/index-BwNqcy-4.css
vendored
Normal file
1
dist/assets/index-BwNqcy-4.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
dist/assets/index-Cx06WFub.js
vendored
Normal file
6
dist/assets/index-Cx06WFub.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/css/index.06951331.css
vendored
1
dist/css/index.06951331.css
vendored
@ -1 +0,0 @@
|
||||
[data-v-9b14a31e]{margin:0;padding:0}.remove-text[data-v-9b14a31e]{text-align:center;padding:20px;font-size:24px}.player-btns[data-v-9b14a31e]{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-wrap:wrap;flex-wrap:wrap}.player-btns span[data-v-9b14a31e]{margin:0 auto;display:inline-block;padding:5px 10px;width:150px;height:40px;line-height:40px;border:1px solid #eee;background:#e1e1e1;border-radius:10px;text-align:center;margin:20px auto;cursor:pointer}
|
||||
15
dist/index.html
vendored
15
dist/index.html
vendored
@ -1 +1,14 @@
|
||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/vue-aliplayer-v2/favicon.ico><title>vue-aliplayer-v2</title><link href=/vue-aliplayer-v2/css/index.06951331.css rel=preload as=style><link href=/vue-aliplayer-v2/js/chunk-vendors.69bad5f4.js rel=preload as=script><link href=/vue-aliplayer-v2/js/index.b7f22f1a.js rel=preload as=script><link href=/vue-aliplayer-v2/css/index.06951331.css rel=stylesheet></head><body><noscript><strong>We're sorry but vue-aliplayer-v2 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/vue-aliplayer-v2/js/chunk-vendors.69bad5f4.js></script><script src=/vue-aliplayer-v2/js/index.b7f22f1a.js></script></body></html>
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" href="/vue-aliplayer-v2/favicon.ico">
|
||||
<title>vue-aliplayer-v2</title>
|
||||
<script type="module" crossorigin src="/vue-aliplayer-v2/assets/index-Cx06WFub.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/vue-aliplayer-v2/assets/index-BwNqcy-4.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
8
dist/js/chunk-vendors.69bad5f4.js
vendored
8
dist/js/chunk-vendors.69bad5f4.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/index.b7f22f1a.js
vendored
2
dist/js/index.b7f22f1a.js
vendored
File diff suppressed because one or more lines are too long
8
env.d.ts
vendored
Normal file
8
env.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue';
|
||||
|
||||
const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>;
|
||||
export default component;
|
||||
}
|
||||
1427
examples/App.vue
1427
examples/App.vue
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import App from './App.vue';
|
||||
import VueAliplayerV2 from '../packages';
|
||||
Vue.use(VueAliplayerV2,{
|
||||
// cssLink: 'https://g.alicdn.com/de/prismplayer/2.8.2/skins/default/aliplayer-min.css',
|
||||
// scriptSrc: 'https://g.alicdn.com/de/prismplayer/2.8.2/aliplayer-min.js'
|
||||
});
|
||||
Vue.config.productionTip = false;
|
||||
new Vue({
|
||||
render: h => h(App),
|
||||
}).$mount('#app');
|
||||
4
examples/main.ts
Normal file
4
examples/main.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
|
||||
createApp(App).mount('#app');
|
||||
13
index.html
Normal file
13
index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<title>vue-aliplayer-v2</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/examples/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,10 +0,0 @@
|
||||
<meta charset="utf-8">
|
||||
<title>vue-aliplayer-v2 demo</title>
|
||||
<script src="./vue-aliplayer-v2.umd.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./vue-aliplayer-v2.css">
|
||||
|
||||
|
||||
<script>
|
||||
console.log(vue-aliplayer-v2)
|
||||
</script>
|
||||
59
lib/types/AliplayerV2/index.vue.d.ts
vendored
Normal file
59
lib/types/AliplayerV2/index.vue.d.ts
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
import type { AliplayerOptions, AliplayerV2Props, VueAliplayerV2Expose } from './types';
|
||||
declare const __VLS_export: import("vue").DefineComponent<AliplayerV2Props, VueAliplayerV2Expose, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
||||
canplay: (payload?: unknown) => any;
|
||||
ended: (payload?: unknown) => any;
|
||||
error: (payload?: unknown) => any;
|
||||
pause: (payload?: unknown) => any;
|
||||
play: (payload?: unknown) => any;
|
||||
playing: (payload?: unknown) => any;
|
||||
timeupdate: (payload?: unknown) => any;
|
||||
waiting: (payload?: unknown) => any;
|
||||
ready: (payload?: unknown) => any;
|
||||
liveStreamStop: (payload?: unknown) => any;
|
||||
onM3u8Retry: (payload?: unknown) => any;
|
||||
hideBar: (payload?: unknown) => any;
|
||||
showBar: (payload?: unknown) => any;
|
||||
snapshoted: (payload?: unknown) => any;
|
||||
requestFullScreen: (payload?: unknown) => any;
|
||||
cancelFullScreen: (payload?: unknown) => any;
|
||||
startSeek: (payload?: unknown) => any;
|
||||
completeSeek: (payload?: unknown) => any;
|
||||
"sdk-error": (error: Error) => any;
|
||||
}, string, import("vue").PublicProps, Readonly<AliplayerV2Props> & Readonly<{
|
||||
onCanplay?: ((payload?: unknown) => any) | undefined;
|
||||
onEnded?: ((payload?: unknown) => any) | undefined;
|
||||
onError?: ((payload?: unknown) => any) | undefined;
|
||||
onPause?: ((payload?: unknown) => any) | undefined;
|
||||
onPlay?: ((payload?: unknown) => any) | undefined;
|
||||
onPlaying?: ((payload?: unknown) => any) | undefined;
|
||||
onTimeupdate?: ((payload?: unknown) => any) | undefined;
|
||||
onWaiting?: ((payload?: unknown) => any) | undefined;
|
||||
onReady?: ((payload?: unknown) => any) | undefined;
|
||||
onLiveStreamStop?: ((payload?: unknown) => any) | undefined;
|
||||
onOnM3u8Retry?: ((payload?: unknown) => any) | undefined;
|
||||
onHideBar?: ((payload?: unknown) => any) | undefined;
|
||||
onShowBar?: ((payload?: unknown) => any) | undefined;
|
||||
onSnapshoted?: ((payload?: unknown) => any) | undefined;
|
||||
onRequestFullScreen?: ((payload?: unknown) => any) | undefined;
|
||||
onCancelFullScreen?: ((payload?: unknown) => any) | undefined;
|
||||
onStartSeek?: ((payload?: unknown) => any) | undefined;
|
||||
onCompleteSeek?: ((payload?: unknown) => any) | undefined;
|
||||
"onSdk-error"?: ((error: Error) => any) | undefined;
|
||||
}>, {
|
||||
source: string | null;
|
||||
autoFormat: boolean;
|
||||
forbidFastForward: boolean;
|
||||
license: import("./types").AliplayerLicense | null;
|
||||
lowLatency: boolean;
|
||||
normalizeSourceUrl: boolean;
|
||||
options: AliplayerOptions | null;
|
||||
sdkVersion: string;
|
||||
cssLink: string;
|
||||
scriptSrc: string;
|
||||
componentScripts: string[];
|
||||
disableTracking: boolean;
|
||||
trackingUrlPatterns: Array<string | RegExp>;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
||||
declare const _default: typeof __VLS_export;
|
||||
export default _default;
|
||||
//# sourceMappingURL=index.vue.d.ts.map
|
||||
12
lib/types/AliplayerV2/sdkLoader.d.ts
vendored
Normal file
12
lib/types/AliplayerV2/sdkLoader.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
export declare const DEFAULT_SDK_VERSION = "2.37.0";
|
||||
export declare const DEFAULT_CSS_LINK = "https://g.alicdn.com/apsara-media-box/imp-web-player/2.37.0/skins/default/aliplayer-min.css";
|
||||
export declare const DEFAULT_SCRIPT_SRC = "https://g.alicdn.com/apsara-media-box/imp-web-player/2.37.0/aliplayer-min.js";
|
||||
export declare function getCssLinkByVersion(version: string): string;
|
||||
export declare function getScriptSrcByVersion(version: string): string;
|
||||
/**
|
||||
* Shared SDK loader. It prevents duplicate CSS/JS tags when several player
|
||||
* instances mount at the same time or are recreated by route changes.
|
||||
*/
|
||||
export declare function loadAliplayerSdk(cssLink: string, scriptSrc: string): Promise<void>;
|
||||
export declare function loadExtraScripts(scriptUrls?: string[]): Promise<void>;
|
||||
//# sourceMappingURL=sdkLoader.d.ts.map
|
||||
4
lib/types/AliplayerV2/source.d.ts
vendored
Normal file
4
lib/types/AliplayerV2/source.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export type SourceFormat = 'mp4' | 'm3u8' | 'flv' | 'rtmp' | 'mp3' | null;
|
||||
export declare function inferSourceFormat(source?: string | null): SourceFormat;
|
||||
export declare function normalizeSource(source?: string | null): string | null;
|
||||
//# sourceMappingURL=source.d.ts.map
|
||||
7
lib/types/AliplayerV2/tracking.d.ts
vendored
Normal file
7
lib/types/AliplayerV2/tracking.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
export declare function installTrackingBlocker(patterns?: Array<string | RegExp>): void;
|
||||
declare global {
|
||||
interface XMLHttpRequest {
|
||||
__vueAliplayerV2Blocked?: boolean;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=tracking.d.ts.map
|
||||
128
lib/types/AliplayerV2/types.d.ts
vendored
Normal file
128
lib/types/AliplayerV2/types.d.ts
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
import type { Plugin } from 'vue';
|
||||
export interface VueAliplayerV2Options {
|
||||
sdkVersion?: string;
|
||||
cssLink?: string;
|
||||
scriptSrc?: string;
|
||||
componentScripts?: string[];
|
||||
disableTracking?: boolean;
|
||||
trackingUrlPatterns?: Array<string | RegExp>;
|
||||
}
|
||||
export interface AliplayerV2Props extends VueAliplayerV2Options {
|
||||
autoFormat?: boolean;
|
||||
forbidFastForward?: boolean;
|
||||
license?: AliplayerLicense | null;
|
||||
lowLatency?: boolean;
|
||||
normalizeSourceUrl?: boolean;
|
||||
options?: AliplayerOptions | null;
|
||||
source?: string | null;
|
||||
}
|
||||
export interface AliplayerLicense {
|
||||
domain: string;
|
||||
key: string;
|
||||
}
|
||||
export type AliplayerEventName = 'ready' | 'play' | 'pause' | 'canplay' | 'playing' | 'ended' | 'liveStreamStop' | 'onM3u8Retry' | 'hideBar' | 'showBar' | 'waiting' | 'timeupdate' | 'snapshoted' | 'requestFullScreen' | 'cancelFullScreen' | 'error' | 'startSeek' | 'completeSeek';
|
||||
export interface AliplayerOptions {
|
||||
id?: string;
|
||||
source?: string;
|
||||
width?: string;
|
||||
autoplay?: boolean;
|
||||
isLive?: boolean;
|
||||
format?: string;
|
||||
license?: AliplayerLicense;
|
||||
vid?: string;
|
||||
playauth?: string;
|
||||
accessKeyId?: string;
|
||||
securityToken?: string;
|
||||
accessKeySecret?: string;
|
||||
region?: string;
|
||||
authTimeout?: number;
|
||||
components?: unknown[];
|
||||
enableStashBufferForFlv?: boolean;
|
||||
stashInitialSizeForFlv?: number;
|
||||
rtsVersion?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
export interface AliplayerFullscreenService {
|
||||
requestFullScreen: () => void;
|
||||
cancelFullScreen: () => void;
|
||||
getIsFullScreen: () => boolean;
|
||||
}
|
||||
export interface AliplayerLiveShiftService {
|
||||
setLiveTimeRange: (beginTime: string, endTime: string) => void;
|
||||
}
|
||||
export interface AliplayerInstance {
|
||||
on: (eventName: string, handler: (event?: unknown) => void) => void;
|
||||
off?: (eventName: string, handler: (event?: unknown) => void) => void;
|
||||
play: () => void;
|
||||
pause: () => void;
|
||||
replay: () => void;
|
||||
seek: (time: number) => void;
|
||||
getCurrentTime: () => number;
|
||||
getDuration: () => number;
|
||||
getVolume: () => number;
|
||||
setVolume: (volume: number) => void;
|
||||
loadByUrl: (url: string, time?: number) => void;
|
||||
replayByVidAndPlayAuth: (vid: string, playauth: string) => void;
|
||||
replayByVidAndAuthInfo: (vid: string, accId: string, accSecret: string, stsToken: string, authInfo: string, domainRegion: string) => void;
|
||||
setPlayerSize: (width: string, height: string) => void;
|
||||
setSpeed: (speed: number) => void;
|
||||
setSanpshotProperties: (width: number, height: number, rate: number) => void;
|
||||
fullscreenService?: AliplayerFullscreenService;
|
||||
getStatus: () => string;
|
||||
liveShiftSerivce?: AliplayerLiveShiftService;
|
||||
setRotate: (rotate: number) => void;
|
||||
getRotate: () => number;
|
||||
setImage: (image: string) => void;
|
||||
dispose: () => void;
|
||||
setCover: (cover: string) => void;
|
||||
setProgressMarkers: (markers: unknown[]) => void;
|
||||
setPreviewTime: (time: number) => void;
|
||||
getPreviewTime: () => number;
|
||||
isPreview: () => boolean;
|
||||
}
|
||||
export interface VueAliplayerV2Expose {
|
||||
getPlayer: () => AliplayerInstance | null;
|
||||
init: () => Promise<void>;
|
||||
initPlayer: () => void;
|
||||
reload: (nextSource?: string) => Promise<void>;
|
||||
retry: (nextSource?: string) => Promise<void>;
|
||||
play: () => void;
|
||||
pause: () => void;
|
||||
replay: () => void;
|
||||
seek: (time: number) => void;
|
||||
getCurrentTime: () => number | undefined;
|
||||
getDuration: () => number | undefined;
|
||||
getVolume: () => number | undefined;
|
||||
setVolume: (volume: number) => void;
|
||||
loadByUrl: (url: string, time?: number) => void;
|
||||
replayByVidAndPlayAuth: (vid: string, playauth: string) => void;
|
||||
replayByVidAndAuthInfo: (vid: string, accId: string, accSecret: string, stsToken: string, authInfo: string, domainRegion: string) => void;
|
||||
setPlayerSize: (width: string, height: string) => void;
|
||||
setSpeed: (speed: number) => void;
|
||||
setSanpshotProperties: (width: number, height: number, rate: number) => void;
|
||||
requestFullScreen: () => void;
|
||||
cancelFullScreen: () => void;
|
||||
getIsFullScreen: () => boolean | undefined;
|
||||
getStatus: () => string | undefined;
|
||||
setLiveTimeRange: (beginTime: string, endTime: string) => void;
|
||||
setRotate: (rotate: number) => void;
|
||||
getRotate: () => number | undefined;
|
||||
setImage: (image: string) => void;
|
||||
dispose: () => void;
|
||||
setCover: (cover: string) => void;
|
||||
setProgressMarkers: (markers: unknown[]) => void;
|
||||
setPreviewTime: (time: number) => void;
|
||||
getPreviewTime: () => number | undefined;
|
||||
isPreview: () => boolean | undefined;
|
||||
off: (eventName: string, handler: (event?: unknown) => void) => void;
|
||||
}
|
||||
export type VueAliplayerV2Plugin = Plugin & {
|
||||
Player?: unknown;
|
||||
};
|
||||
declare global {
|
||||
interface Window {
|
||||
Aliplayer?: (options: AliplayerOptions) => AliplayerInstance;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=types.d.ts.map
|
||||
32
lib/types/index.d.ts
vendored
Normal file
32
lib/types/index.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
import type { App } from 'vue';
|
||||
import VueAliplayerV2 from './AliplayerV2/index.vue';
|
||||
import type { VueAliplayerV2Options } from './AliplayerV2/types';
|
||||
export type { AliplayerEventName, AliplayerInstance, AliplayerLicense, AliplayerOptions, AliplayerV2Props, VueAliplayerV2Expose, VueAliplayerV2Options } from './AliplayerV2/types';
|
||||
type InstallableVueAliplayerV2 = typeof VueAliplayerV2 & {
|
||||
install: (app: App, options?: VueAliplayerV2Options) => void;
|
||||
Player: typeof VueAliplayerV2;
|
||||
props: {
|
||||
sdkVersion: {
|
||||
default: string | (() => string);
|
||||
};
|
||||
cssLink: {
|
||||
default: string | (() => string);
|
||||
};
|
||||
scriptSrc: {
|
||||
default: string | (() => string);
|
||||
};
|
||||
componentScripts: {
|
||||
default: string[] | (() => string[]);
|
||||
};
|
||||
disableTracking: {
|
||||
default: boolean | (() => boolean);
|
||||
};
|
||||
trackingUrlPatterns: {
|
||||
default: Array<string | RegExp> | (() => Array<string | RegExp>);
|
||||
};
|
||||
};
|
||||
};
|
||||
declare const installable: InstallableVueAliplayerV2;
|
||||
export { installable as VueAliplayerV2 };
|
||||
export default installable;
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
File diff suppressed because it is too large
Load Diff
2
lib/vue-aliplayer-v2.css
Normal file
2
lib/vue-aliplayer-v2.css
Normal file
@ -0,0 +1,2 @@
|
||||
.vue-aliplayer-v2[data-v-cf852d0d]{width:100%}
|
||||
/*$vite$:1*/
|
||||
395
lib/vue-aliplayer-v2.js
Normal file
395
lib/vue-aliplayer-v2.js
Normal file
@ -0,0 +1,395 @@
|
||||
import { computed as e, createElementBlock as t, defineComponent as n, nextTick as r, onBeforeUnmount as i, onMounted as a, openBlock as o, ref as s, watch as c } from "vue";
|
||||
//#region packages/AliplayerV2/sdkLoader.ts
|
||||
var l = "2.37.0", u = `https://g.alicdn.com/apsara-media-box/imp-web-player/${l}/skins/default/aliplayer-min.css`, d = `https://g.alicdn.com/apsara-media-box/imp-web-player/${l}/aliplayer-min.js`, f = /* @__PURE__ */ new Map();
|
||||
function p(e) {
|
||||
return `https://g.alicdn.com/apsara-media-box/imp-web-player/${e}/skins/default/aliplayer-min.css`;
|
||||
}
|
||||
function m(e) {
|
||||
return `https://g.alicdn.com/apsara-media-box/imp-web-player/${e}/aliplayer-min.js`;
|
||||
}
|
||||
function h(e) {
|
||||
if (!e || document.querySelector(`link[data-vue-aliplayer-v2-css="${e}"]`)) return;
|
||||
let t = document.createElement("link");
|
||||
t.type = "text/css", t.rel = "stylesheet", t.href = e, t.dataset.vueAliplayerV2Css = e, document.head.appendChild(t);
|
||||
}
|
||||
function g(e, t) {
|
||||
if (!e || t && window[t]) return Promise.resolve();
|
||||
if (f.has(e)) return f.get(e);
|
||||
let n = document.querySelector(`script[data-vue-aliplayer-v2-js="${e}"]`);
|
||||
if (n) {
|
||||
let t = new Promise((t, r) => {
|
||||
if (n.dataset.vueAliplayerV2Loaded === "true") {
|
||||
t();
|
||||
return;
|
||||
}
|
||||
n.addEventListener("load", () => {
|
||||
n.dataset.vueAliplayerV2Loaded = "true", t();
|
||||
}, { once: !0 }), n.addEventListener("error", () => r(/* @__PURE__ */ Error(`Failed to load Aliplayer SDK: ${e}`)), { once: !0 });
|
||||
});
|
||||
return f.set(e, t), t;
|
||||
}
|
||||
let r = new Promise((t, n) => {
|
||||
let r = document.createElement("script");
|
||||
r.type = "text/javascript", r.src = e, r.dataset.vueAliplayerV2Js = e, r.addEventListener("load", () => {
|
||||
r.dataset.vueAliplayerV2Loaded = "true", t();
|
||||
}, { once: !0 }), r.addEventListener("error", () => n(/* @__PURE__ */ Error(`Failed to load Aliplayer SDK: ${e}`)), { once: !0 }), document.documentElement.appendChild(r);
|
||||
});
|
||||
return f.set(e, r), r;
|
||||
}
|
||||
async function _(e, t) {
|
||||
h(e), await g(t, "Aliplayer");
|
||||
}
|
||||
async function v(e = []) {
|
||||
for (let t of e) await g(t);
|
||||
}
|
||||
//#endregion
|
||||
//#region packages/AliplayerV2/source.ts
|
||||
var y = [
|
||||
"m3u8",
|
||||
"flv",
|
||||
"mp4",
|
||||
"rtmp",
|
||||
"mp3"
|
||||
];
|
||||
function b(e) {
|
||||
if (!e) return null;
|
||||
if (/^rtmps?:\/\//i.test(e)) return "rtmp";
|
||||
let t = e.split("?")[0].split("#")[0].toLowerCase();
|
||||
return y.find((e) => e && t.endsWith(`.${e}`)) || null;
|
||||
}
|
||||
function x(e) {
|
||||
if (!e) return e || null;
|
||||
if (/^(data|blob):/i.test(e)) return e;
|
||||
try {
|
||||
return encodeURI(e);
|
||||
} catch {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
//#region packages/AliplayerV2/tracking.ts
|
||||
var S = ["videocloud.cn-hangzhou.log.aliyuncs.com/logstores/newplayer/track"], C = !1;
|
||||
function w(e, t) {
|
||||
return t.some((t) => typeof t == "string" ? e.includes(t) : t.test(e));
|
||||
}
|
||||
function T(e = S) {
|
||||
if (C) return;
|
||||
C = !0;
|
||||
let t = window.fetch?.bind(window);
|
||||
t && (window.fetch = ((n, r) => w(typeof n == "string" || n instanceof URL ? String(n) : n.url, e) ? Promise.resolve(new Response(null, {
|
||||
status: 204,
|
||||
statusText: "No Content"
|
||||
})) : t(n, r)));
|
||||
let n = XMLHttpRequest.prototype.open, r = XMLHttpRequest.prototype.send;
|
||||
XMLHttpRequest.prototype.open = function(t, r, i, a, o) {
|
||||
this.__vueAliplayerV2Blocked = w(String(r), e), n.call(this, t, r, i ?? !0, a ?? void 0, o ?? void 0);
|
||||
}, XMLHttpRequest.prototype.send = function(e) {
|
||||
this.__vueAliplayerV2Blocked || r.call(this, e);
|
||||
};
|
||||
}
|
||||
//#endregion
|
||||
//#region packages/AliplayerV2/index.vue
|
||||
var E = /* @__PURE__ */ ((e, t) => {
|
||||
let n = e.__vccOpts || e;
|
||||
for (let [e, r] of t) n[e] = r;
|
||||
return n;
|
||||
})(/* @__PURE__ */ n({
|
||||
name: "VueAliplayerV2",
|
||||
__name: "index",
|
||||
props: {
|
||||
autoFormat: {
|
||||
type: Boolean,
|
||||
default: !0
|
||||
},
|
||||
forbidFastForward: {
|
||||
type: Boolean,
|
||||
default: !1
|
||||
},
|
||||
license: { default: null },
|
||||
lowLatency: {
|
||||
type: Boolean,
|
||||
default: !1
|
||||
},
|
||||
normalizeSourceUrl: {
|
||||
type: Boolean,
|
||||
default: !0
|
||||
},
|
||||
options: { default: null },
|
||||
source: { default: null },
|
||||
sdkVersion: { default: l },
|
||||
cssLink: { default: "" },
|
||||
scriptSrc: { default: "" },
|
||||
componentScripts: { default: () => [] },
|
||||
disableTracking: {
|
||||
type: Boolean,
|
||||
default: !1
|
||||
},
|
||||
trackingUrlPatterns: { default: () => [] }
|
||||
},
|
||||
emits: [
|
||||
"ready",
|
||||
"play",
|
||||
"pause",
|
||||
"canplay",
|
||||
"playing",
|
||||
"ended",
|
||||
"liveStreamStop",
|
||||
"onM3u8Retry",
|
||||
"hideBar",
|
||||
"showBar",
|
||||
"waiting",
|
||||
"timeupdate",
|
||||
"snapshoted",
|
||||
"requestFullScreen",
|
||||
"cancelFullScreen",
|
||||
"error",
|
||||
"startSeek",
|
||||
"completeSeek",
|
||||
"sdk-error"
|
||||
],
|
||||
setup(n, { expose: l, emit: f }) {
|
||||
let h = n, g = f, y = s(null), S = s(null), C = s(!1), w = s(null), E = 0, D = `player-${Math.random().toString(36).slice(2).toUpperCase()}`, O = [
|
||||
"ready",
|
||||
"play",
|
||||
"pause",
|
||||
"canplay",
|
||||
"playing",
|
||||
"ended",
|
||||
"liveStreamStop",
|
||||
"onM3u8Retry",
|
||||
"hideBar",
|
||||
"showBar",
|
||||
"waiting",
|
||||
"timeupdate",
|
||||
"snapshoted",
|
||||
"requestFullScreen",
|
||||
"cancelFullScreen",
|
||||
"error",
|
||||
"startSeek",
|
||||
"completeSeek"
|
||||
], k = e(() => h.cssLink || (h.sdkVersion ? p(h.sdkVersion) : u)), A = e(() => h.scriptSrc || (h.sdkVersion ? m(h.sdkVersion) : d)), j = e(() => h.normalizeSourceUrl ? x(h.source) : h.source), M = e(() => b(j.value)), N = e(() => {
|
||||
let e = {
|
||||
width: "100%",
|
||||
autoplay: !0,
|
||||
...h.options || {},
|
||||
...h.license ? { license: h.license } : {},
|
||||
...j.value ? { source: j.value } : {},
|
||||
id: D
|
||||
};
|
||||
return h.autoFormat && M.value && !e.format && (e.format = M.value), h.lowLatency && e.isLive && M.value === "flv" && (e.enableStashBufferForFlv = e.enableStashBufferForFlv ?? !1, e.stashInitialSizeForFlv = e.stashInitialSizeForFlv ?? 128), e;
|
||||
});
|
||||
function P() {
|
||||
return y.value;
|
||||
}
|
||||
function F() {
|
||||
y.value && (y.value.dispose(), y.value = null, w.value = null);
|
||||
}
|
||||
function I(e) {
|
||||
O.forEach((t) => {
|
||||
e.on(t, (e) => {
|
||||
g(t, e);
|
||||
});
|
||||
});
|
||||
}
|
||||
function L(e) {
|
||||
if (!h.forbidFastForward) return;
|
||||
let t = 0, n = 0;
|
||||
e.on("timeupdate", () => {
|
||||
let r = e.getCurrentTime();
|
||||
if (r - t > 2) {
|
||||
e.seek(t);
|
||||
return;
|
||||
}
|
||||
t = r, t >= n && (n = t);
|
||||
});
|
||||
}
|
||||
function R() {
|
||||
if (C.value || !window.Aliplayer || !S.value) return;
|
||||
F();
|
||||
let e = window.Aliplayer({ ...N.value });
|
||||
y.value = e, w.value = M.value, I(e), L(e);
|
||||
}
|
||||
async function z() {
|
||||
let e = ++E;
|
||||
try {
|
||||
if (h.disableTracking && T(h.trackingUrlPatterns), await _(k.value, A.value), await v(h.componentScripts), await r(), C.value || e !== E) return;
|
||||
R();
|
||||
} catch (e) {
|
||||
g("sdk-error", e instanceof Error ? e : Error(String(e)));
|
||||
}
|
||||
}
|
||||
async function B(e) {
|
||||
if (e && y.value) {
|
||||
y.value.loadByUrl(h.normalizeSourceUrl && x(e) || e);
|
||||
return;
|
||||
}
|
||||
await z();
|
||||
}
|
||||
async function V(e) {
|
||||
await B(e);
|
||||
}
|
||||
function H() {
|
||||
y.value?.play();
|
||||
}
|
||||
function U() {
|
||||
y.value?.pause();
|
||||
}
|
||||
function W() {
|
||||
y.value?.replay();
|
||||
}
|
||||
function G(e) {
|
||||
y.value?.seek(e);
|
||||
}
|
||||
function K() {
|
||||
return y.value?.getCurrentTime();
|
||||
}
|
||||
function ee() {
|
||||
return y.value?.getDuration();
|
||||
}
|
||||
function q() {
|
||||
return y.value?.getVolume();
|
||||
}
|
||||
function J(e) {
|
||||
y.value?.setVolume(e);
|
||||
}
|
||||
function Y(e, t) {
|
||||
y.value?.loadByUrl(e, t);
|
||||
}
|
||||
function X(e, t) {
|
||||
y.value?.replayByVidAndPlayAuth(e, t);
|
||||
}
|
||||
function Z(e, t, n, r, i, a) {
|
||||
y.value?.replayByVidAndAuthInfo(e, t, n, r, i, a);
|
||||
}
|
||||
function Q(e, t) {
|
||||
y.value?.setPlayerSize(e, t);
|
||||
}
|
||||
function $(e) {
|
||||
y.value?.setSpeed(e);
|
||||
}
|
||||
function te(e, t, n) {
|
||||
y.value?.setSanpshotProperties(e, t, n);
|
||||
}
|
||||
function ne() {
|
||||
y.value?.fullscreenService?.requestFullScreen();
|
||||
}
|
||||
function re() {
|
||||
y.value?.fullscreenService?.cancelFullScreen();
|
||||
}
|
||||
function ie() {
|
||||
return y.value?.fullscreenService?.getIsFullScreen();
|
||||
}
|
||||
function ae() {
|
||||
return y.value?.getStatus();
|
||||
}
|
||||
function oe(e, t) {
|
||||
y.value?.liveShiftSerivce?.setLiveTimeRange(e, t);
|
||||
}
|
||||
function se(e) {
|
||||
y.value?.setRotate(e);
|
||||
}
|
||||
function ce() {
|
||||
return y.value?.getRotate();
|
||||
}
|
||||
function le(e) {
|
||||
y.value?.setImage(e);
|
||||
}
|
||||
function ue(e) {
|
||||
y.value?.setCover(e);
|
||||
}
|
||||
function de(e) {
|
||||
y.value?.setProgressMarkers(e);
|
||||
}
|
||||
function fe(e) {
|
||||
y.value?.setPreviewTime(e);
|
||||
}
|
||||
function pe() {
|
||||
return y.value?.getPreviewTime();
|
||||
}
|
||||
function me() {
|
||||
return y.value?.isPreview();
|
||||
}
|
||||
function he(e, t) {
|
||||
y.value?.off?.(e, t);
|
||||
}
|
||||
return a(() => {
|
||||
z();
|
||||
}), c(() => j.value, (e) => {
|
||||
if (!e) return;
|
||||
let t = b(e);
|
||||
if (y.value && t && t === w.value) {
|
||||
y.value.loadByUrl(e);
|
||||
return;
|
||||
}
|
||||
z();
|
||||
}), c(() => [
|
||||
h.options,
|
||||
h.forbidFastForward,
|
||||
h.license,
|
||||
h.lowLatency,
|
||||
h.autoFormat,
|
||||
h.sdkVersion,
|
||||
h.cssLink,
|
||||
h.scriptSrc,
|
||||
h.componentScripts,
|
||||
h.disableTracking,
|
||||
h.trackingUrlPatterns
|
||||
], () => {
|
||||
z();
|
||||
}, { deep: !0 }), i(() => {
|
||||
C.value = !0, E += 1, F();
|
||||
}), l({
|
||||
getPlayer: P,
|
||||
init: z,
|
||||
initPlayer: R,
|
||||
reload: B,
|
||||
retry: V,
|
||||
play: H,
|
||||
pause: U,
|
||||
replay: W,
|
||||
seek: G,
|
||||
getCurrentTime: K,
|
||||
getDuration: ee,
|
||||
getVolume: q,
|
||||
setVolume: J,
|
||||
loadByUrl: Y,
|
||||
replayByVidAndPlayAuth: X,
|
||||
replayByVidAndAuthInfo: Z,
|
||||
setPlayerSize: Q,
|
||||
setSpeed: $,
|
||||
setSanpshotProperties: te,
|
||||
requestFullScreen: ne,
|
||||
cancelFullScreen: re,
|
||||
getIsFullScreen: ie,
|
||||
getStatus: ae,
|
||||
setLiveTimeRange: oe,
|
||||
setRotate: se,
|
||||
getRotate: ce,
|
||||
setImage: le,
|
||||
dispose: F,
|
||||
setCover: ue,
|
||||
setProgressMarkers: de,
|
||||
setPreviewTime: fe,
|
||||
getPreviewTime: pe,
|
||||
isPreview: me,
|
||||
off: he
|
||||
}), (e, n) => (o(), t("div", {
|
||||
id: D,
|
||||
ref_key: "containerRef",
|
||||
ref: S,
|
||||
class: "vue-aliplayer-v2"
|
||||
}, null, 512));
|
||||
}
|
||||
}), [["__scopeId", "data-v-cf852d0d"]]), D = {
|
||||
sdkVersion: l,
|
||||
cssLink: u,
|
||||
scriptSrc: d,
|
||||
componentScripts: [],
|
||||
disableTracking: !1,
|
||||
trackingUrlPatterns: []
|
||||
}, O = E;
|
||||
O.install = (e, t) => {
|
||||
Object.assign(D, t || {}), e.component("VueAliplayerV2", O);
|
||||
}, O.props.cssLink.default = () => D.cssLink, O.props.scriptSrc.default = () => D.scriptSrc, O.props.sdkVersion.default = () => D.sdkVersion, O.props.componentScripts.default = () => D.componentScripts, O.props.disableTracking.default = () => D.disableTracking, O.props.trackingUrlPatterns.default = () => D.trackingUrlPatterns, O.Player = O;
|
||||
//#endregion
|
||||
export { O as VueAliplayerV2, O as default };
|
||||
1
lib/vue-aliplayer-v2.umd.cjs
Normal file
1
lib/vue-aliplayer-v2.umd.cjs
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
2
lib/vue-aliplayer-v2.umd.min.js
vendored
2
lib/vue-aliplayer-v2.umd.min.js
vendored
File diff suppressed because one or more lines are too long
1250
package-lock.json
generated
Normal file
1250
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
48
package.json
48
package.json
@ -1,34 +1,44 @@
|
||||
{
|
||||
"name": "vue-aliplayer-v2",
|
||||
"version": "1.3.1",
|
||||
"version": "2.0.0",
|
||||
"type": "module",
|
||||
"author": "yxs",
|
||||
"description": "感谢每一位支持开源的朋友. 这是一个基于Alipayer 开发并封装成vue组件的集成播放器.可播放rtmp,m3u8,mp4....视频.除支持直播流与点播的基础功能外,也支持视频的加密播放、清晰度切换、直播时移等业务场景",
|
||||
"main": "lib/vue-aliplayer-v2.umd.min.js",
|
||||
"description": "Vue 3 wrapper for Aliyun Aliplayer. Supports mp4, m3u8, flv, live streams, encrypted playback, quality switching, and live time shift through the official Aliplayer SDK.",
|
||||
"main": "lib/vue-aliplayer-v2.umd.cjs",
|
||||
"module": "lib/vue-aliplayer-v2.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"import": "./lib/vue-aliplayer-v2.js",
|
||||
"require": "./lib/vue-aliplayer-v2.umd.cjs"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"README.md"
|
||||
],
|
||||
"private": false,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"lib": "vue-cli-service build --target lib --name vue-aliplayer-v2 --dest lib packages/index.js"
|
||||
"dev": "vite --host 0.0.0.0",
|
||||
"build": "vite build --mode demo",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"lib": "vue-tsc -p tsconfig.build.json --declaration --emitDeclarationOnly --outDir lib/types && vite build --mode lib",
|
||||
"lint": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^2.6.5",
|
||||
"vue": "^2.6.10"
|
||||
"vue": "^3.5.34"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.8.0",
|
||||
"@vue/cli-plugin-eslint": "^3.8.0",
|
||||
"@vue/cli-service": "^3.8.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^5.0.0",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
"@types/node": "^24.10.0",
|
||||
"@vitejs/plugin-vue": "^6.0.7",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^8.0.14",
|
||||
"vue-tsc": "^3.3.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:langyuxiansheng/vue-aliplayer-v2.git"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,555 +1,386 @@
|
||||
<template>
|
||||
<div :id="playerId"></div>
|
||||
<div :id="playerId" ref="containerRef" class="vue-aliplayer-v2"></div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'VueAliplayerV2',
|
||||
props: {
|
||||
forbidFastForward: { //禁止拖拽快进
|
||||
required: false,
|
||||
type: [Boolean],
|
||||
default: false
|
||||
},
|
||||
options: { //配置项
|
||||
required: false,
|
||||
type: [Object],
|
||||
default: () => null
|
||||
},
|
||||
source: { //播放源(此属性存在则优先于options.source) 动态切换,目前只支持同种格式(mp4/flv/m3u8)之间切换。暂不支持直播rtmp流切换。
|
||||
required: false,
|
||||
type: [String],
|
||||
default: null
|
||||
},
|
||||
cssLink: { //css版本源
|
||||
required: false,
|
||||
type: [String],
|
||||
default: `https://g.alicdn.com/de/prismplayer/2.9.20/skins/default/aliplayer-min.css`
|
||||
},
|
||||
scriptSrc: { //js版本源
|
||||
required: false,
|
||||
type: [String],
|
||||
default: `https://g.alicdn.com/de/prismplayer/2.9.20/aliplayer-min.js`
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
player: null, //播放器实例
|
||||
playerId: `player-${Math.random().toString(36).substr(2).toLocaleUpperCase()}`,
|
||||
config: {
|
||||
id: null, //播放器的ID
|
||||
width: '100%',
|
||||
autoplay: true,
|
||||
// isLive: true,
|
||||
//支持播放地址播放,此播放优先级最高
|
||||
// source: 'rtmp://182.145.195.238:1935/hls/1194076936807170050',
|
||||
},
|
||||
events: [
|
||||
/**
|
||||
* 播放器视频初始化按钮渲染完毕。
|
||||
* 播放器UI初始设置需要此事件后触发,避免UI被初始化所覆盖。
|
||||
* 播放器提供的方法需要在此事件发生后才可以调用。
|
||||
*/
|
||||
'ready',
|
||||
/**
|
||||
* 视频由暂停恢复为播放时触发。
|
||||
*/
|
||||
'play',
|
||||
/**
|
||||
* 视频暂停时触发。
|
||||
*/
|
||||
'pause',
|
||||
/**
|
||||
* 能够开始播放音频/视频时发生,会多次触发,仅H5播放器。
|
||||
*/
|
||||
'canplay',
|
||||
/**
|
||||
* 播放中,会触发多次。
|
||||
*/
|
||||
'playing',
|
||||
/**
|
||||
* 当前视频播放完毕时触发。
|
||||
*/
|
||||
'ended',
|
||||
/**
|
||||
* 直播流中断时触发。
|
||||
* m3u8/flv/rtmp在重试5次未成功后触发。
|
||||
* 提示上层流中断或需要重新加载视频。
|
||||
* PS:m3u8一直自动重试,不需要上层添加重试。
|
||||
*/
|
||||
'liveStreamStop',
|
||||
/**
|
||||
* m3u8直播流中断后重试事件,每次断流只触发一次。
|
||||
*/
|
||||
'onM3u8Retry',
|
||||
/**
|
||||
* 控制栏自动隐藏事件。
|
||||
*/
|
||||
'hideBar',
|
||||
/**
|
||||
* 控制栏自动显示事件。
|
||||
*/
|
||||
'showBar',
|
||||
/**
|
||||
* 数据缓冲事件。
|
||||
*/
|
||||
'waiting',
|
||||
/**
|
||||
* 播放位置发生改变时触发,仅H5播放器。
|
||||
* 可通过getCurrentTime方法,得到当前播放时间。
|
||||
*/
|
||||
'timeupdate',
|
||||
/**
|
||||
* 截图完成。
|
||||
*/
|
||||
'snapshoted',
|
||||
/**
|
||||
* 全屏事件,仅H5支持。
|
||||
*/
|
||||
'requestFullScreen',
|
||||
/**
|
||||
* 取消全屏事件,iOS下不会触发,仅H5支持。
|
||||
*/
|
||||
'cancelFullScreen',
|
||||
/**
|
||||
* 错误事件。
|
||||
*/
|
||||
'error',
|
||||
/**
|
||||
* 开始拖拽,参数返回拖拽点的时间。
|
||||
*/
|
||||
'startSeek',
|
||||
/**
|
||||
* 完成拖拽,参数返回拖拽点的时间。
|
||||
*/
|
||||
'completeSeek'
|
||||
],
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
source () { //监听播放源变化
|
||||
this.init();
|
||||
},
|
||||
forbidFastForward () {
|
||||
this.init();
|
||||
|
||||
},
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import {
|
||||
DEFAULT_CSS_LINK,
|
||||
DEFAULT_SCRIPT_SRC,
|
||||
DEFAULT_SDK_VERSION,
|
||||
getCssLinkByVersion,
|
||||
getScriptSrcByVersion,
|
||||
loadAliplayerSdk,
|
||||
loadExtraScripts
|
||||
} from './sdkLoader';
|
||||
import { inferSourceFormat, normalizeSource, type SourceFormat } from './source';
|
||||
import { installTrackingBlocker } from './tracking';
|
||||
import type {
|
||||
AliplayerEventName,
|
||||
AliplayerInstance,
|
||||
AliplayerOptions,
|
||||
AliplayerV2Props,
|
||||
VueAliplayerV2Expose
|
||||
} from './types';
|
||||
|
||||
options: { //配置项是对象,只能深度监听
|
||||
handler () {
|
||||
this.init();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.init();
|
||||
});
|
||||
},
|
||||
updated () {
|
||||
//重载播放器
|
||||
this.$nextTick(() => {
|
||||
this.init();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
handlerFastForward () {
|
||||
defineOptions({
|
||||
name: 'VueAliplayerV2'
|
||||
});
|
||||
|
||||
},
|
||||
/**
|
||||
* 创建script和css
|
||||
* 加载Alipayer的SDK
|
||||
*/
|
||||
init () {
|
||||
const linkID = 'app__aliplayer-min-css';
|
||||
const scriptID = 'app__aliplayer-min-js';
|
||||
const head = document.getElementsByTagName('head');
|
||||
const html = document.getElementsByTagName('html');
|
||||
let scriptTag = document.getElementById(scriptID);
|
||||
let linkIDTag = document.getElementById(linkID);
|
||||
if (!linkIDTag) {
|
||||
// console.log('linkIDTag');
|
||||
const link = document.createElement('link');
|
||||
link.type = 'text/css';
|
||||
link.rel = 'stylesheet';
|
||||
link.href = this.cssLink;
|
||||
link.id = linkID;
|
||||
// link.className = linkID;
|
||||
head[0].appendChild(link);
|
||||
}
|
||||
if (!scriptTag) {
|
||||
// console.log('scriptTag');
|
||||
scriptTag = document.createElement('script');
|
||||
scriptTag.type = "text/javascript";
|
||||
scriptTag.id = scriptID;
|
||||
// scriptTag.className = scriptID;
|
||||
scriptTag.src = this.scriptSrc;
|
||||
html[0].appendChild(scriptTag);
|
||||
} else {
|
||||
this.initPlayer(); //这样是为了兼容页面上有多个播放器
|
||||
}
|
||||
//兼容单页加载和硬加载
|
||||
scriptTag.addEventListener("load", () => {
|
||||
this.initPlayer();
|
||||
});
|
||||
},
|
||||
const props = withDefaults(defineProps<AliplayerV2Props>(), {
|
||||
autoFormat: true,
|
||||
componentScripts: () => [],
|
||||
disableTracking: false,
|
||||
forbidFastForward: false,
|
||||
license: null,
|
||||
lowLatency: false,
|
||||
normalizeSourceUrl: true,
|
||||
options: null,
|
||||
sdkVersion: DEFAULT_SDK_VERSION,
|
||||
source: null,
|
||||
cssLink: '',
|
||||
scriptSrc: '',
|
||||
trackingUrlPatterns: () => []
|
||||
});
|
||||
|
||||
/**
|
||||
* 创建播放器
|
||||
* @description SDK文档地址:https://help.aliyun.com/document_detail/125572.html?spm=a2c4g.11186623.6.1084.131d1c4cJT7o5Z
|
||||
*/
|
||||
initPlayer () {
|
||||
if (typeof window.Aliplayer != 'undefined') {
|
||||
const options = this.deepCloneObject(this.options);
|
||||
if (options) {
|
||||
for (const key in options) {
|
||||
this.config[key] = options[key];
|
||||
}
|
||||
}
|
||||
if (this.source) this.config.source = this.source; //播放源
|
||||
this.config.id = this.playerId; //赋值播放器容器id
|
||||
this.player && this.player.dispose(); //防止实例的重复
|
||||
this.player = Aliplayer(this.config);
|
||||
for (const ev in this.events) {
|
||||
this.player && this.player.on(this.events[ev], (e) => {
|
||||
// console.log(`object ${this.events[ev]}`,e);
|
||||
this.$emit(this.events[ev], e);
|
||||
});
|
||||
}
|
||||
const emit = defineEmits<{
|
||||
(event: AliplayerEventName, payload?: unknown): void;
|
||||
(event: 'sdk-error', error: Error): void;
|
||||
}>();
|
||||
|
||||
const player = ref<AliplayerInstance | null>(null);
|
||||
const containerRef = ref<HTMLDivElement | null>(null);
|
||||
const isUnmounted = ref(false);
|
||||
const currentFormat = ref<SourceFormat>(null);
|
||||
let initToken = 0;
|
||||
const playerId = `player-${Math.random().toString(36).slice(2).toUpperCase()}`;
|
||||
const eventNames: AliplayerEventName[] = [
|
||||
'ready',
|
||||
'play',
|
||||
'pause',
|
||||
'canplay',
|
||||
'playing',
|
||||
'ended',
|
||||
'liveStreamStop',
|
||||
'onM3u8Retry',
|
||||
'hideBar',
|
||||
'showBar',
|
||||
'waiting',
|
||||
'timeupdate',
|
||||
'snapshoted',
|
||||
'requestFullScreen',
|
||||
'cancelFullScreen',
|
||||
'error',
|
||||
'startSeek',
|
||||
'completeSeek'
|
||||
];
|
||||
|
||||
//开启禁止拖拽快进
|
||||
if (this.forbidFastForward) {
|
||||
let last = 0, max_time = 0;
|
||||
this.player.on('timeupdate', function () {
|
||||
let current = this.getCurrentTime();
|
||||
if (current - last > 2) {
|
||||
this.seek(last);
|
||||
} else {
|
||||
last = current;
|
||||
if (last >= max_time) {
|
||||
max_time = last;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const resolvedCssLink = computed(() => props.cssLink || (props.sdkVersion ? getCssLinkByVersion(props.sdkVersion) : DEFAULT_CSS_LINK));
|
||||
const resolvedScriptSrc = computed(() => props.scriptSrc || (props.sdkVersion ? getScriptSrcByVersion(props.sdkVersion) : DEFAULT_SCRIPT_SRC));
|
||||
const normalizedSource = computed(() => props.normalizeSourceUrl ? normalizeSource(props.source) : props.source);
|
||||
const sourceFormat = computed(() => inferSourceFormat(normalizedSource.value));
|
||||
const mergedOptions = computed<AliplayerOptions>(() => {
|
||||
const options: AliplayerOptions = {
|
||||
width: '100%',
|
||||
autoplay: true,
|
||||
...(props.options || {}),
|
||||
...(props.license ? { license: props.license } : {}),
|
||||
...(normalizedSource.value ? { source: normalizedSource.value } : {}),
|
||||
id: playerId
|
||||
};
|
||||
|
||||
//通过播放器实例的off方法取消订阅
|
||||
//player.off('ready',handleReady);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @return player 实例
|
||||
*/
|
||||
getPlayer () {
|
||||
return this.player;
|
||||
},
|
||||
|
||||
/**
|
||||
* 播放视频。
|
||||
*/
|
||||
play () {
|
||||
// console.log(`播放视频。`);
|
||||
this.player && this.player.play();
|
||||
},
|
||||
|
||||
/**
|
||||
* 暂停视频
|
||||
*/
|
||||
pause () {
|
||||
// console.log(`暂停视频`);
|
||||
this.player && this.player.pause();
|
||||
},
|
||||
|
||||
/**
|
||||
* 重播视频
|
||||
*/
|
||||
replay () {
|
||||
// console.log(`重播视频`);
|
||||
this.player && this.player.replay();
|
||||
},
|
||||
|
||||
/**
|
||||
* 跳转到某个时刻进行播放,time的单位为秒。
|
||||
* @param time
|
||||
* @return player
|
||||
*/
|
||||
seek (time) {
|
||||
// console.log(`跳转到某个时刻进行播放,time为${time}秒。`);
|
||||
this.player && this.player.seek(time);
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取当前的播放时刻,返回的单位为秒。
|
||||
* @return player
|
||||
*/
|
||||
getCurrentTime () {
|
||||
// console.log(`获取当前的播放时刻,返回的单位为${this.player && this.player.getCurrentTime()}秒。`);
|
||||
return this.player && this.player.getCurrentTime();
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取视频总时长,返回的单位为秒,这个需要在视频加载完成以后才可以获取到,可以在play事件后获取。
|
||||
* @return player
|
||||
*/
|
||||
getDuration () {
|
||||
// console.log(`获取视频总时长,返回的单位为${this.player && this.player.getDuration()}秒。`);
|
||||
return this.player && this.player.getDuration();
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取当前的音量,返回值为0-1的实数。ios和部分android会失效。
|
||||
* @return player
|
||||
*/
|
||||
getVolume () {
|
||||
// console.log(`获取当前的音量${this.player && this.player.getVolume()}。`);
|
||||
return this.player && this.player.getVolume();
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置音量,vol为0-1的实数,ios和部分android会失效。
|
||||
* @return player
|
||||
*/
|
||||
setVolume (v) {
|
||||
// console.log(`设置音量,vol为${v}。`);
|
||||
this.player && this.player.setVolume(v);
|
||||
},
|
||||
|
||||
/**
|
||||
* 直接播放视频url,time为可选值(单位秒)。目前只支持同种格式(mp4/flv/m3u8)之间切换。
|
||||
* 暂不支持直播rtmp流切换。
|
||||
* @return player
|
||||
*/
|
||||
loadByUrl (url, time) {
|
||||
// console.log(`直接播放视频url${url},time为${time}。`);
|
||||
this.player && this.player.loadByUrl(url, time);
|
||||
},
|
||||
|
||||
/**
|
||||
* 目前只支持H5播放器。暂不支持不同格式视频间的之间切换。暂不支持直播rtmp流切换。
|
||||
* @param vid 视频id
|
||||
* @param 播放凭证
|
||||
*/
|
||||
replayByVidAndPlayAuth (vid, playauth) {
|
||||
// console.log(`replayByVidAndPlayAuth vid${vid},playauth为${playauth}。`);
|
||||
this.player && this.player.replayByVidAndPlayAuth(vid, playauth);
|
||||
},
|
||||
|
||||
/**
|
||||
* 目前只支持H5播放器。暂不支持不同格式视频间的之间切换。暂不支持直播rtmp流切换。
|
||||
* @param vid 视频id
|
||||
* @param 播放凭证
|
||||
* @description 仅MPS用户时使用 仅MPS用户时使用 参数顺序为:vid、accId、accSecret、stsToken、authInfo、domainRegion
|
||||
*/
|
||||
replayByVidAndAuthInfo (vid, accId, accSecret, stsToken, authInfo, domainRegion) {
|
||||
// console.log(`replayByVidAndAuthInfo 参数顺序为:vid、accId、accSecret、stsToken、authInfo、domainRegion`,vid, accId, accSecret, stsToken, authInfo, domainRegion);
|
||||
this.player && this.player.replayByVidAndAuthInfo(vid, accId, accSecret, stsToken, authInfo, domainRegion);
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置播放器大小w,h可分别为400px像素或60%百分比。
|
||||
* @param w 宽度
|
||||
* @param h 宽度
|
||||
* @description chrome浏览器下flash播放器分别不能小于397x297。
|
||||
*/
|
||||
setPlayerSize (w, h) {
|
||||
// console.log(`设置播放器大小 宽度:${w},高度:${h}`);
|
||||
this.player && this.player.setPlayerSize(w, h);
|
||||
},
|
||||
|
||||
/**
|
||||
* 手动设置播放的倍速,倍速播放仅H5支持。移动端可能会失效,比如android微信。
|
||||
* 倍速播放UI默认是开启的。
|
||||
* 如果自定义过skinLaout属性,需要添加speedButton项到数组里:
|
||||
* @param h 宽度
|
||||
* @description {name:“speedButton”,align:“tr”,x:10,y:23}
|
||||
*/
|
||||
setSpeed (speed) {
|
||||
// console.log(`手动设置播放的倍速:${speed}`);
|
||||
this.player && this.player.setSpeed(speed);
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置截图参数
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param rate 截图质量
|
||||
*/
|
||||
setSanpshotProperties (width, height, rate) {
|
||||
// console.log(`设置截图参数:`,width, height, rate);
|
||||
this.player && this.player.setSanpshotProperties(width, height, rate);
|
||||
},
|
||||
|
||||
/**
|
||||
* 播放器全屏,仅H5支持。
|
||||
*/
|
||||
requestFullScreen () {
|
||||
// console.log(`播放器全屏,仅H5支持`);
|
||||
this.player && this.player.fullscreenService && this.player.fullscreenService.requestFullScreen();
|
||||
},
|
||||
|
||||
/**
|
||||
* 播放器退出全屏,iOS调用无效,仅H5支持。
|
||||
*/
|
||||
cancelFullScreen () {
|
||||
// console.log(`播放器全屏,仅H5支持`);
|
||||
this.player && this.player.fullscreenService && this.player.fullscreenService.cancelFullScreen();
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取播放器全屏状态,仅H5支持。
|
||||
*/
|
||||
getIsFullScreen () {
|
||||
// console.log(`获取播放器全屏状态,仅H5支持。`,this.player && this.player.fullscreenService && this.player && this.player.fullscreenService.getIsFullScreen());
|
||||
return this.player && this.player.fullscreenService && this.player.fullscreenService.getIsFullScreen();
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取播放器状态,包含的值,
|
||||
* @returns init ready loading play pause playing waiting error ended
|
||||
*/
|
||||
getStatus () {
|
||||
// console.log(`获取播放器状态,包含的值`,this.player && this.player.fullscreenService && this.player && this.player.fullscreenService.getStatus());
|
||||
return this.player && this.player.getStatus();
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置直播的开始结束时间,开启直播时移功能时使用。
|
||||
* @param beginTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @description 例子:player.liveShiftSerivce.setLiveTimeRange(“”,‘2018/01/04 20:00:00’)
|
||||
*/
|
||||
setLiveTimeRange (beginTime, endTime) {
|
||||
// console.log(`设置直播的开始时间:${beginTime},结束时间:${endTime},开启直播时移功能时使用。`);
|
||||
this.player && this.player.liveShiftSerivce && this.player.liveShiftSerivce.setLiveTimeRange(beginTime, endTime);
|
||||
},
|
||||
|
||||
/**
|
||||
* 参数为旋转角度, 正数为正时针旋转, 负数为逆时针旋转。
|
||||
* @param rotate 旋转角度
|
||||
* @description 例如: setRotate(90)。详情参见旋转和镜像。
|
||||
*/
|
||||
setRotate (rotate) {
|
||||
// console.log(`参数为旋转角度:${rotate}。`);
|
||||
this.player && this.player.setRotate(rotate);
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取旋转角度。详情参见旋转和镜像。
|
||||
* @return rotate 旋转角度
|
||||
*/
|
||||
getRotate () {
|
||||
// console.log(`获取旋转角度:${this.player && this.player.getRotate()}`);
|
||||
return this.player && this.player.getRotate();
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置镜像
|
||||
* @param image 镜像类型 可选值为:horizon,vertical
|
||||
* @description 例如: setImage(‘horizon’)。详情参见旋转和镜像。
|
||||
*/
|
||||
setImage (image) {
|
||||
// console.log(`设置镜像:${image}。`);
|
||||
this.player && this.player.setImage(image);
|
||||
},
|
||||
|
||||
/**
|
||||
* 播放器销毁
|
||||
*/
|
||||
dispose () {
|
||||
// console.log(`播放器销毁。`);
|
||||
this.player && this.player.dispose();
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置封面
|
||||
* @param cover 封面地址
|
||||
*/
|
||||
setCover (cover) {
|
||||
// console.log(`设置封面:${cover}`);
|
||||
this.player && this.player.setCover(cover);
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置封面
|
||||
* @param markers 设置打点数据
|
||||
*/
|
||||
setProgressMarkers (markers) {
|
||||
// console.log(`markers打点数据集合:${markers}`);
|
||||
this.player && this.player.setProgressMarkers(markers);
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置试看时间,单位为秒,详情参见
|
||||
* @param time 试看时间
|
||||
*/
|
||||
setPreviewTime (time) {
|
||||
// console.log(`设置试看时间,单位为:${time}秒`);
|
||||
this.player && this.player.setPreviewTime(time);
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取试看时间
|
||||
* @return rotate 旋转角度
|
||||
*/
|
||||
getPreviewTime () {
|
||||
// console.log(`获取试看时间:${this.player && this.player.getPreviewTime()}`);
|
||||
return this.player && this.player.getPreviewTime();
|
||||
},
|
||||
|
||||
/**
|
||||
* 是否试看
|
||||
*/
|
||||
isPreview () {
|
||||
// console.log(`是否试看`);
|
||||
this.player && this.player.isPreview();
|
||||
},
|
||||
|
||||
/**
|
||||
* @param ev 事件名
|
||||
* @param handle 回调方法
|
||||
*/
|
||||
off (ev, handle) {
|
||||
this.player && this.player.off(ev, handle);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 深度拷贝
|
||||
* @param {*} obj
|
||||
*/
|
||||
deepCloneObject (obj) {
|
||||
let objClone = Array.isArray(obj) ? [] : {};
|
||||
if (obj && typeof obj === 'object') {
|
||||
for (let key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
//判断ojb子元素是否为对象,如果是,递归复制
|
||||
if (obj[key] && typeof obj[key] === 'object') {
|
||||
objClone[key] = this.deepCloneObject(obj[key]);
|
||||
} else {
|
||||
//如果不是,简单复制
|
||||
objClone[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return objClone;
|
||||
}
|
||||
|
||||
},
|
||||
beforeDestroy () { //防止重复创建
|
||||
this.dispose(); //销毁播放器(防止直播播放的情况下,播放器已经销毁,而后台还在继续下载资源造成卡顿的bug)
|
||||
// const head = document.querySelector('head');
|
||||
// const cssNodes = document.querySelectorAll(`link.app__aliplayer-min-css`);
|
||||
// (html && cssNodes.length > 1) && cssNodes.forEach((item, index)=>{
|
||||
// if(index != 0) head.removeChild(item);
|
||||
// });
|
||||
// const html = document.querySelector('html');
|
||||
// const jsNodes = document.querySelectorAll(`script.app__aliplayer-min-js`);
|
||||
// (html && jsNodes.length > 1) && jsNodes.forEach((item, index)=>{
|
||||
// if(index != 0) html.removeChild(item);
|
||||
// });
|
||||
if (props.autoFormat && sourceFormat.value && !options.format) {
|
||||
options.format = sourceFormat.value;
|
||||
}
|
||||
};
|
||||
|
||||
if (props.lowLatency && options.isLive && sourceFormat.value === 'flv') {
|
||||
options.enableStashBufferForFlv = options.enableStashBufferForFlv ?? false;
|
||||
options.stashInitialSizeForFlv = options.stashInitialSizeForFlv ?? 128;
|
||||
}
|
||||
|
||||
return options;
|
||||
});
|
||||
|
||||
function getPlayer(): AliplayerInstance | null {
|
||||
return player.value;
|
||||
}
|
||||
|
||||
function dispose(): void {
|
||||
if (!player.value) return;
|
||||
player.value.dispose();
|
||||
player.value = null;
|
||||
currentFormat.value = null;
|
||||
}
|
||||
|
||||
function bindEvents(target: AliplayerInstance): void {
|
||||
eventNames.forEach((eventName) => {
|
||||
target.on(eventName, (event?: unknown) => {
|
||||
emit(eventName, event);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function bindForbidFastForward(target: AliplayerInstance): void {
|
||||
if (!props.forbidFastForward) return;
|
||||
|
||||
let last = 0;
|
||||
let maxTime = 0;
|
||||
target.on('timeupdate', () => {
|
||||
const current = target.getCurrentTime();
|
||||
if (current - last > 2) {
|
||||
target.seek(last);
|
||||
return;
|
||||
}
|
||||
|
||||
last = current;
|
||||
if (last >= maxTime) {
|
||||
maxTime = last;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initPlayer(): void {
|
||||
if (isUnmounted.value || !window.Aliplayer || !containerRef.value) return;
|
||||
|
||||
dispose();
|
||||
const nextPlayer = window.Aliplayer({ ...mergedOptions.value });
|
||||
player.value = nextPlayer;
|
||||
currentFormat.value = sourceFormat.value;
|
||||
bindEvents(nextPlayer);
|
||||
bindForbidFastForward(nextPlayer);
|
||||
}
|
||||
|
||||
async function init(): Promise<void> {
|
||||
const token = ++initToken;
|
||||
try {
|
||||
if (props.disableTracking) {
|
||||
installTrackingBlocker(props.trackingUrlPatterns);
|
||||
}
|
||||
await loadAliplayerSdk(resolvedCssLink.value, resolvedScriptSrc.value);
|
||||
await loadExtraScripts(props.componentScripts);
|
||||
await nextTick();
|
||||
if (isUnmounted.value || token !== initToken) return;
|
||||
initPlayer();
|
||||
} catch (error) {
|
||||
emit('sdk-error', error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
}
|
||||
|
||||
async function reload(nextSource?: string): Promise<void> {
|
||||
if (nextSource && player.value) {
|
||||
player.value.loadByUrl(props.normalizeSourceUrl ? normalizeSource(nextSource) || nextSource : nextSource);
|
||||
return;
|
||||
}
|
||||
|
||||
await init();
|
||||
}
|
||||
|
||||
async function retry(nextSource?: string): Promise<void> {
|
||||
await reload(nextSource);
|
||||
}
|
||||
|
||||
function play(): void {
|
||||
player.value?.play();
|
||||
}
|
||||
|
||||
function pause(): void {
|
||||
player.value?.pause();
|
||||
}
|
||||
|
||||
function replay(): void {
|
||||
player.value?.replay();
|
||||
}
|
||||
|
||||
function seek(time: number): void {
|
||||
player.value?.seek(time);
|
||||
}
|
||||
|
||||
function getCurrentTime(): number | undefined {
|
||||
return player.value?.getCurrentTime();
|
||||
}
|
||||
|
||||
function getDuration(): number | undefined {
|
||||
return player.value?.getDuration();
|
||||
}
|
||||
|
||||
function getVolume(): number | undefined {
|
||||
return player.value?.getVolume();
|
||||
}
|
||||
|
||||
function setVolume(volume: number): void {
|
||||
player.value?.setVolume(volume);
|
||||
}
|
||||
|
||||
function loadByUrl(url: string, time?: number): void {
|
||||
player.value?.loadByUrl(url, time);
|
||||
}
|
||||
|
||||
function replayByVidAndPlayAuth(vid: string, playauth: string): void {
|
||||
player.value?.replayByVidAndPlayAuth(vid, playauth);
|
||||
}
|
||||
|
||||
function replayByVidAndAuthInfo(
|
||||
vid: string,
|
||||
accId: string,
|
||||
accSecret: string,
|
||||
stsToken: string,
|
||||
authInfo: string,
|
||||
domainRegion: string
|
||||
): void {
|
||||
player.value?.replayByVidAndAuthInfo(vid, accId, accSecret, stsToken, authInfo, domainRegion);
|
||||
}
|
||||
|
||||
function setPlayerSize(width: string, height: string): void {
|
||||
player.value?.setPlayerSize(width, height);
|
||||
}
|
||||
|
||||
function setSpeed(speed: number): void {
|
||||
player.value?.setSpeed(speed);
|
||||
}
|
||||
|
||||
function setSanpshotProperties(width: number, height: number, rate: number): void {
|
||||
player.value?.setSanpshotProperties(width, height, rate);
|
||||
}
|
||||
|
||||
function requestFullScreen(): void {
|
||||
player.value?.fullscreenService?.requestFullScreen();
|
||||
}
|
||||
|
||||
function cancelFullScreen(): void {
|
||||
player.value?.fullscreenService?.cancelFullScreen();
|
||||
}
|
||||
|
||||
function getIsFullScreen(): boolean | undefined {
|
||||
return player.value?.fullscreenService?.getIsFullScreen();
|
||||
}
|
||||
|
||||
function getStatus(): string | undefined {
|
||||
return player.value?.getStatus();
|
||||
}
|
||||
|
||||
function setLiveTimeRange(beginTime: string, endTime: string): void {
|
||||
player.value?.liveShiftSerivce?.setLiveTimeRange(beginTime, endTime);
|
||||
}
|
||||
|
||||
function setRotate(rotate: number): void {
|
||||
player.value?.setRotate(rotate);
|
||||
}
|
||||
|
||||
function getRotate(): number | undefined {
|
||||
return player.value?.getRotate();
|
||||
}
|
||||
|
||||
function setImage(image: string): void {
|
||||
player.value?.setImage(image);
|
||||
}
|
||||
|
||||
function setCover(cover: string): void {
|
||||
player.value?.setCover(cover);
|
||||
}
|
||||
|
||||
function setProgressMarkers(markers: unknown[]): void {
|
||||
player.value?.setProgressMarkers(markers);
|
||||
}
|
||||
|
||||
function setPreviewTime(time: number): void {
|
||||
player.value?.setPreviewTime(time);
|
||||
}
|
||||
|
||||
function getPreviewTime(): number | undefined {
|
||||
return player.value?.getPreviewTime();
|
||||
}
|
||||
|
||||
function isPreview(): boolean | undefined {
|
||||
return player.value?.isPreview();
|
||||
}
|
||||
|
||||
function off(eventName: string, handler: (event?: unknown) => void): void {
|
||||
player.value?.off?.(eventName, handler);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void init();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => normalizedSource.value,
|
||||
(source) => {
|
||||
if (!source) return;
|
||||
const nextFormat = inferSourceFormat(source);
|
||||
if (player.value && nextFormat && nextFormat === currentFormat.value) {
|
||||
player.value.loadByUrl(source);
|
||||
return;
|
||||
}
|
||||
void init();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => [
|
||||
props.options,
|
||||
props.forbidFastForward,
|
||||
props.license,
|
||||
props.lowLatency,
|
||||
props.autoFormat,
|
||||
props.sdkVersion,
|
||||
props.cssLink,
|
||||
props.scriptSrc,
|
||||
props.componentScripts,
|
||||
props.disableTracking,
|
||||
props.trackingUrlPatterns
|
||||
],
|
||||
() => {
|
||||
void init();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
isUnmounted.value = true;
|
||||
initToken += 1;
|
||||
dispose();
|
||||
});
|
||||
|
||||
defineExpose<VueAliplayerV2Expose>({
|
||||
getPlayer,
|
||||
init,
|
||||
initPlayer,
|
||||
reload,
|
||||
retry,
|
||||
play,
|
||||
pause,
|
||||
replay,
|
||||
seek,
|
||||
getCurrentTime,
|
||||
getDuration,
|
||||
getVolume,
|
||||
setVolume,
|
||||
loadByUrl,
|
||||
replayByVidAndPlayAuth,
|
||||
replayByVidAndAuthInfo,
|
||||
setPlayerSize,
|
||||
setSpeed,
|
||||
setSanpshotProperties,
|
||||
requestFullScreen,
|
||||
cancelFullScreen,
|
||||
getIsFullScreen,
|
||||
getStatus,
|
||||
setLiveTimeRange,
|
||||
setRotate,
|
||||
getRotate,
|
||||
setImage,
|
||||
dispose,
|
||||
setCover,
|
||||
setProgressMarkers,
|
||||
setPreviewTime,
|
||||
getPreviewTime,
|
||||
isPreview,
|
||||
off
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.vue-aliplayer-v2 {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
81
packages/AliplayerV2/sdkLoader.ts
Normal file
81
packages/AliplayerV2/sdkLoader.ts
Normal file
@ -0,0 +1,81 @@
|
||||
export const DEFAULT_SDK_VERSION = '2.37.0';
|
||||
export const DEFAULT_CSS_LINK = `https://g.alicdn.com/apsara-media-box/imp-web-player/${DEFAULT_SDK_VERSION}/skins/default/aliplayer-min.css`;
|
||||
export const DEFAULT_SCRIPT_SRC = `https://g.alicdn.com/apsara-media-box/imp-web-player/${DEFAULT_SDK_VERSION}/aliplayer-min.js`;
|
||||
|
||||
const scriptLoadPromises = new Map<string, Promise<void>>();
|
||||
|
||||
export function getCssLinkByVersion(version: string): string {
|
||||
return `https://g.alicdn.com/apsara-media-box/imp-web-player/${version}/skins/default/aliplayer-min.css`;
|
||||
}
|
||||
|
||||
export function getScriptSrcByVersion(version: string): string {
|
||||
return `https://g.alicdn.com/apsara-media-box/imp-web-player/${version}/aliplayer-min.js`;
|
||||
}
|
||||
|
||||
function ensureStylesheet(cssLink: string): void {
|
||||
if (!cssLink) return;
|
||||
|
||||
const existed = document.querySelector<HTMLLinkElement>(`link[data-vue-aliplayer-v2-css="${cssLink}"]`);
|
||||
if (existed) return;
|
||||
|
||||
const link = document.createElement('link');
|
||||
link.type = 'text/css';
|
||||
link.rel = 'stylesheet';
|
||||
link.href = cssLink;
|
||||
link.dataset.vueAliplayerV2Css = cssLink;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
function ensureScript(scriptSrc: string, globalName?: string): Promise<void> {
|
||||
if (!scriptSrc) return Promise.resolve();
|
||||
if (globalName && window[globalName]) return Promise.resolve();
|
||||
if (scriptLoadPromises.has(scriptSrc)) return scriptLoadPromises.get(scriptSrc) as Promise<void>;
|
||||
|
||||
const existed = document.querySelector<HTMLScriptElement>(`script[data-vue-aliplayer-v2-js="${scriptSrc}"]`);
|
||||
if (existed) {
|
||||
const loadPromise = new Promise<void>((resolve, reject) => {
|
||||
if (existed.dataset.vueAliplayerV2Loaded === 'true') {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
existed.addEventListener('load', () => {
|
||||
existed.dataset.vueAliplayerV2Loaded = 'true';
|
||||
resolve();
|
||||
}, { once: true });
|
||||
existed.addEventListener('error', () => reject(new Error(`Failed to load Aliplayer SDK: ${scriptSrc}`)), { once: true });
|
||||
});
|
||||
scriptLoadPromises.set(scriptSrc, loadPromise);
|
||||
return loadPromise;
|
||||
}
|
||||
|
||||
const loadPromise = new Promise<void>((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = scriptSrc;
|
||||
script.dataset.vueAliplayerV2Js = scriptSrc;
|
||||
script.addEventListener('load', () => {
|
||||
script.dataset.vueAliplayerV2Loaded = 'true';
|
||||
resolve();
|
||||
}, { once: true });
|
||||
script.addEventListener('error', () => reject(new Error(`Failed to load Aliplayer SDK: ${scriptSrc}`)), { once: true });
|
||||
document.documentElement.appendChild(script);
|
||||
});
|
||||
|
||||
scriptLoadPromises.set(scriptSrc, loadPromise);
|
||||
return loadPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared SDK loader. It prevents duplicate CSS/JS tags when several player
|
||||
* instances mount at the same time or are recreated by route changes.
|
||||
*/
|
||||
export async function loadAliplayerSdk(cssLink: string, scriptSrc: string): Promise<void> {
|
||||
ensureStylesheet(cssLink);
|
||||
await ensureScript(scriptSrc, 'Aliplayer');
|
||||
}
|
||||
|
||||
export async function loadExtraScripts(scriptUrls: string[] = []): Promise<void> {
|
||||
for (const scriptUrl of scriptUrls) {
|
||||
await ensureScript(scriptUrl);
|
||||
}
|
||||
}
|
||||
25
packages/AliplayerV2/source.ts
Normal file
25
packages/AliplayerV2/source.ts
Normal file
@ -0,0 +1,25 @@
|
||||
export type SourceFormat = 'mp4' | 'm3u8' | 'flv' | 'rtmp' | 'mp3' | null;
|
||||
|
||||
const KNOWN_FORMATS: SourceFormat[] = ['m3u8', 'flv', 'mp4', 'rtmp', 'mp3'];
|
||||
|
||||
export function inferSourceFormat(source?: string | null): SourceFormat {
|
||||
if (!source) return null;
|
||||
|
||||
if (/^rtmps?:\/\//i.test(source)) return 'rtmp';
|
||||
|
||||
const cleanSource = source.split('?')[0].split('#')[0].toLowerCase();
|
||||
const matched = KNOWN_FORMATS.find((format) => format && cleanSource.endsWith(`.${format}`));
|
||||
return matched || null;
|
||||
}
|
||||
|
||||
export function normalizeSource(source?: string | null): string | null {
|
||||
if (!source) return source || null;
|
||||
if (/^(data|blob):/i.test(source)) return source;
|
||||
|
||||
try {
|
||||
return encodeURI(source);
|
||||
} catch {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
49
packages/AliplayerV2/tracking.ts
Normal file
49
packages/AliplayerV2/tracking.ts
Normal file
@ -0,0 +1,49 @@
|
||||
const DEFAULT_TRACKING_PATTERNS: Array<string | RegExp> = [
|
||||
'videocloud.cn-hangzhou.log.aliyuncs.com/logstores/newplayer/track'
|
||||
];
|
||||
|
||||
let trackingBlockerInstalled = false;
|
||||
|
||||
function matchesTrackingUrl(url: string, patterns: Array<string | RegExp>): boolean {
|
||||
return patterns.some((pattern) => {
|
||||
if (typeof pattern === 'string') return url.includes(pattern);
|
||||
return pattern.test(url);
|
||||
});
|
||||
}
|
||||
|
||||
export function installTrackingBlocker(patterns: Array<string | RegExp> = DEFAULT_TRACKING_PATTERNS): void {
|
||||
if (trackingBlockerInstalled) return;
|
||||
trackingBlockerInstalled = true;
|
||||
|
||||
const originalFetch = window.fetch?.bind(window);
|
||||
if (originalFetch) {
|
||||
window.fetch = ((input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const url = typeof input === 'string' || input instanceof URL ? String(input) : input.url;
|
||||
if (matchesTrackingUrl(url, patterns)) {
|
||||
return Promise.resolve(new Response(null, { status: 204, statusText: 'No Content' }));
|
||||
}
|
||||
return originalFetch(input, init);
|
||||
}) as typeof window.fetch;
|
||||
}
|
||||
|
||||
const originalOpen = XMLHttpRequest.prototype.open;
|
||||
const originalSend = XMLHttpRequest.prototype.send;
|
||||
|
||||
XMLHttpRequest.prototype.open = function open(method: string, url: string | URL, async?: boolean, username?: string | null, password?: string | null): void {
|
||||
this.__vueAliplayerV2Blocked = matchesTrackingUrl(String(url), patterns);
|
||||
originalOpen.call(this, method, url, async ?? true, username ?? undefined, password ?? undefined);
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.send = function send(body?: Document | XMLHttpRequestBodyInit | null): void {
|
||||
if (this.__vueAliplayerV2Blocked) {
|
||||
return;
|
||||
}
|
||||
originalSend.call(this, body);
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface XMLHttpRequest {
|
||||
__vueAliplayerV2Blocked?: boolean;
|
||||
}
|
||||
}
|
||||
170
packages/AliplayerV2/types.ts
Normal file
170
packages/AliplayerV2/types.ts
Normal file
@ -0,0 +1,170 @@
|
||||
import type { Plugin } from 'vue';
|
||||
|
||||
export interface VueAliplayerV2Options {
|
||||
sdkVersion?: string;
|
||||
cssLink?: string;
|
||||
scriptSrc?: string;
|
||||
componentScripts?: string[];
|
||||
disableTracking?: boolean;
|
||||
trackingUrlPatterns?: Array<string | RegExp>;
|
||||
}
|
||||
|
||||
export interface AliplayerV2Props extends VueAliplayerV2Options {
|
||||
autoFormat?: boolean;
|
||||
forbidFastForward?: boolean;
|
||||
license?: AliplayerLicense | null;
|
||||
lowLatency?: boolean;
|
||||
normalizeSourceUrl?: boolean;
|
||||
options?: AliplayerOptions | null;
|
||||
source?: string | null;
|
||||
}
|
||||
|
||||
export interface AliplayerLicense {
|
||||
domain: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
export type AliplayerEventName =
|
||||
| 'ready'
|
||||
| 'play'
|
||||
| 'pause'
|
||||
| 'canplay'
|
||||
| 'playing'
|
||||
| 'ended'
|
||||
| 'liveStreamStop'
|
||||
| 'onM3u8Retry'
|
||||
| 'hideBar'
|
||||
| 'showBar'
|
||||
| 'waiting'
|
||||
| 'timeupdate'
|
||||
| 'snapshoted'
|
||||
| 'requestFullScreen'
|
||||
| 'cancelFullScreen'
|
||||
| 'error'
|
||||
| 'startSeek'
|
||||
| 'completeSeek';
|
||||
|
||||
export interface AliplayerOptions {
|
||||
id?: string;
|
||||
source?: string;
|
||||
width?: string;
|
||||
autoplay?: boolean;
|
||||
isLive?: boolean;
|
||||
format?: string;
|
||||
license?: AliplayerLicense;
|
||||
vid?: string;
|
||||
playauth?: string;
|
||||
accessKeyId?: string;
|
||||
securityToken?: string;
|
||||
accessKeySecret?: string;
|
||||
region?: string;
|
||||
authTimeout?: number;
|
||||
components?: unknown[];
|
||||
enableStashBufferForFlv?: boolean;
|
||||
stashInitialSizeForFlv?: number;
|
||||
rtsVersion?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface AliplayerFullscreenService {
|
||||
requestFullScreen: () => void;
|
||||
cancelFullScreen: () => void;
|
||||
getIsFullScreen: () => boolean;
|
||||
}
|
||||
|
||||
export interface AliplayerLiveShiftService {
|
||||
setLiveTimeRange: (beginTime: string, endTime: string) => void;
|
||||
}
|
||||
|
||||
export interface AliplayerInstance {
|
||||
on: (eventName: string, handler: (event?: unknown) => void) => void;
|
||||
off?: (eventName: string, handler: (event?: unknown) => void) => void;
|
||||
play: () => void;
|
||||
pause: () => void;
|
||||
replay: () => void;
|
||||
seek: (time: number) => void;
|
||||
getCurrentTime: () => number;
|
||||
getDuration: () => number;
|
||||
getVolume: () => number;
|
||||
setVolume: (volume: number) => void;
|
||||
loadByUrl: (url: string, time?: number) => void;
|
||||
replayByVidAndPlayAuth: (vid: string, playauth: string) => void;
|
||||
replayByVidAndAuthInfo: (
|
||||
vid: string,
|
||||
accId: string,
|
||||
accSecret: string,
|
||||
stsToken: string,
|
||||
authInfo: string,
|
||||
domainRegion: string
|
||||
) => void;
|
||||
setPlayerSize: (width: string, height: string) => void;
|
||||
setSpeed: (speed: number) => void;
|
||||
setSanpshotProperties: (width: number, height: number, rate: number) => void;
|
||||
fullscreenService?: AliplayerFullscreenService;
|
||||
getStatus: () => string;
|
||||
liveShiftSerivce?: AliplayerLiveShiftService;
|
||||
setRotate: (rotate: number) => void;
|
||||
getRotate: () => number;
|
||||
setImage: (image: string) => void;
|
||||
dispose: () => void;
|
||||
setCover: (cover: string) => void;
|
||||
setProgressMarkers: (markers: unknown[]) => void;
|
||||
setPreviewTime: (time: number) => void;
|
||||
getPreviewTime: () => number;
|
||||
isPreview: () => boolean;
|
||||
}
|
||||
|
||||
export interface VueAliplayerV2Expose {
|
||||
getPlayer: () => AliplayerInstance | null;
|
||||
init: () => Promise<void>;
|
||||
initPlayer: () => void;
|
||||
reload: (nextSource?: string) => Promise<void>;
|
||||
retry: (nextSource?: string) => Promise<void>;
|
||||
play: () => void;
|
||||
pause: () => void;
|
||||
replay: () => void;
|
||||
seek: (time: number) => void;
|
||||
getCurrentTime: () => number | undefined;
|
||||
getDuration: () => number | undefined;
|
||||
getVolume: () => number | undefined;
|
||||
setVolume: (volume: number) => void;
|
||||
loadByUrl: (url: string, time?: number) => void;
|
||||
replayByVidAndPlayAuth: (vid: string, playauth: string) => void;
|
||||
replayByVidAndAuthInfo: (
|
||||
vid: string,
|
||||
accId: string,
|
||||
accSecret: string,
|
||||
stsToken: string,
|
||||
authInfo: string,
|
||||
domainRegion: string
|
||||
) => void;
|
||||
setPlayerSize: (width: string, height: string) => void;
|
||||
setSpeed: (speed: number) => void;
|
||||
setSanpshotProperties: (width: number, height: number, rate: number) => void;
|
||||
requestFullScreen: () => void;
|
||||
cancelFullScreen: () => void;
|
||||
getIsFullScreen: () => boolean | undefined;
|
||||
getStatus: () => string | undefined;
|
||||
setLiveTimeRange: (beginTime: string, endTime: string) => void;
|
||||
setRotate: (rotate: number) => void;
|
||||
getRotate: () => number | undefined;
|
||||
setImage: (image: string) => void;
|
||||
dispose: () => void;
|
||||
setCover: (cover: string) => void;
|
||||
setProgressMarkers: (markers: unknown[]) => void;
|
||||
setPreviewTime: (time: number) => void;
|
||||
getPreviewTime: () => number | undefined;
|
||||
isPreview: () => boolean | undefined;
|
||||
off: (eventName: string, handler: (event?: unknown) => void) => void;
|
||||
}
|
||||
|
||||
export type VueAliplayerV2Plugin = Plugin & {
|
||||
Player?: unknown;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Aliplayer?: (options: AliplayerOptions) => AliplayerInstance;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
// packages / index.js
|
||||
// 导入单个组件
|
||||
import VueAliplayerV2 from './AliplayerV2';
|
||||
// 定义 install 方法
|
||||
VueAliplayerV2.install = (Vue, options) =>{
|
||||
if(options && options.cssLink) VueAliplayerV2.props.cssLink.default = options.cssLink;
|
||||
if(options && options.scriptSrc) VueAliplayerV2.props.scriptSrc.default = options.scriptSrc;
|
||||
Vue.component(VueAliplayerV2.name, VueAliplayerV2);
|
||||
};
|
||||
VueAliplayerV2.Player = VueAliplayerV2;
|
||||
export default VueAliplayerV2;
|
||||
54
packages/index.ts
Normal file
54
packages/index.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import type { App } from 'vue';
|
||||
import VueAliplayerV2 from './AliplayerV2/index.vue';
|
||||
import { DEFAULT_CSS_LINK, DEFAULT_SCRIPT_SRC, DEFAULT_SDK_VERSION } from './AliplayerV2/sdkLoader';
|
||||
import type { VueAliplayerV2Options } from './AliplayerV2/types';
|
||||
|
||||
export type {
|
||||
AliplayerEventName,
|
||||
AliplayerInstance,
|
||||
AliplayerLicense,
|
||||
AliplayerOptions,
|
||||
AliplayerV2Props,
|
||||
VueAliplayerV2Expose,
|
||||
VueAliplayerV2Options
|
||||
} from './AliplayerV2/types';
|
||||
|
||||
type InstallableVueAliplayerV2 = typeof VueAliplayerV2 & {
|
||||
install: (app: App, options?: VueAliplayerV2Options) => void;
|
||||
Player: typeof VueAliplayerV2;
|
||||
props: {
|
||||
sdkVersion: { default: string | (() => string) };
|
||||
cssLink: { default: string | (() => string) };
|
||||
scriptSrc: { default: string | (() => string) };
|
||||
componentScripts: { default: string[] | (() => string[]) };
|
||||
disableTracking: { default: boolean | (() => boolean) };
|
||||
trackingUrlPatterns: { default: Array<string | RegExp> | (() => Array<string | RegExp>) };
|
||||
};
|
||||
};
|
||||
|
||||
const globalOptions: Required<VueAliplayerV2Options> = {
|
||||
sdkVersion: DEFAULT_SDK_VERSION,
|
||||
cssLink: DEFAULT_CSS_LINK,
|
||||
scriptSrc: DEFAULT_SCRIPT_SRC,
|
||||
componentScripts: [],
|
||||
disableTracking: false,
|
||||
trackingUrlPatterns: []
|
||||
};
|
||||
|
||||
const installable = VueAliplayerV2 as unknown as InstallableVueAliplayerV2;
|
||||
|
||||
installable.install = (app: App, options?: VueAliplayerV2Options): void => {
|
||||
Object.assign(globalOptions, options || {});
|
||||
app.component('VueAliplayerV2', installable);
|
||||
};
|
||||
|
||||
installable.props.cssLink.default = (): string => globalOptions.cssLink;
|
||||
installable.props.scriptSrc.default = (): string => globalOptions.scriptSrc;
|
||||
installable.props.sdkVersion.default = (): string => globalOptions.sdkVersion;
|
||||
installable.props.componentScripts.default = (): string[] => globalOptions.componentScripts;
|
||||
installable.props.disableTracking.default = (): boolean => globalOptions.disableTracking;
|
||||
installable.props.trackingUrlPatterns.default = (): Array<string | RegExp> => globalOptions.trackingUrlPatterns;
|
||||
installable.Player = installable;
|
||||
|
||||
export { installable as VueAliplayerV2 };
|
||||
export default installable;
|
||||
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>vue-aliplayer-v2</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but vue-aliplayer-v2 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
5
tsconfig.build.json
Normal file
5
tsconfig.build.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["packages/**/*.ts", "packages/**/*.vue", "env.d.ts"],
|
||||
"exclude": ["examples/**", "dist/**", "lib/**", "node_modules/**"]
|
||||
}
|
||||
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": [
|
||||
"env.d.ts",
|
||||
"examples/**/*.ts",
|
||||
"examples/**/*.vue",
|
||||
"packages/**/*.ts",
|
||||
"packages/**/*.vue",
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
36
vite.config.ts
Normal file
36
vite.config.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const isDemoBuild = mode === 'demo';
|
||||
|
||||
return {
|
||||
base: isDemoBuild ? '/vue-aliplayer-v2/' : '/',
|
||||
plugins: [vue()],
|
||||
publicDir: isDemoBuild ? 'public' : false,
|
||||
build: isDemoBuild
|
||||
? {
|
||||
outDir: 'dist',
|
||||
emptyOutDir: true
|
||||
}
|
||||
: {
|
||||
outDir: 'lib',
|
||||
emptyOutDir: false,
|
||||
lib: {
|
||||
entry: resolve(__dirname, 'packages/index.ts'),
|
||||
name: 'VueAliplayerV2',
|
||||
fileName: 'vue-aliplayer-v2'
|
||||
},
|
||||
rollupOptions: {
|
||||
external: ['vue'],
|
||||
output: {
|
||||
exports: 'named',
|
||||
globals: {
|
||||
vue: 'Vue'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@ -1,15 +0,0 @@
|
||||
// vue.config.js
|
||||
module.exports = {
|
||||
// 将 examples 目录添加为新的页面
|
||||
pages: {
|
||||
index: {
|
||||
// page 的入口
|
||||
entry: 'examples/main.js',
|
||||
// 模板来源
|
||||
template: 'public/index.html',
|
||||
// 输出文件名
|
||||
filename: 'index.html'
|
||||
}
|
||||
},
|
||||
publicPath: process.env.NODE_ENV === "production" ? "/vue-aliplayer-v2" : "/"
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user