|
@@ -1,6 +1,6 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="page-container">
|
|
<div class="page-container">
|
|
|
- <el-card header="Cloudflare Stream 配置">
|
|
|
|
|
|
|
+ <el-card :header="t('Cloudflare Stream 配置')">
|
|
|
<el-form :model="config" label-width="160px" style="max-width: 600px">
|
|
<el-form :model="config" label-width="160px" style="max-width: 600px">
|
|
|
<el-form-item label="Account ID" required>
|
|
<el-form-item label="Account ID" required>
|
|
|
<el-input v-model="config.accountId" placeholder="Cloudflare Account ID" />
|
|
<el-input v-model="config.accountId" placeholder="Cloudflare Account ID" />
|
|
@@ -12,7 +12,7 @@
|
|
|
<template #prepend>customer-</template>
|
|
<template #prepend>customer-</template>
|
|
|
<template #append>.cloudflarestream.com</template>
|
|
<template #append>.cloudflarestream.com</template>
|
|
|
</el-input>
|
|
</el-input>
|
|
|
- <div class="form-tip">播放域名的子域名部分</div>
|
|
|
|
|
|
|
+ <div class="form-tip">{{ t('播放域名的子域名部分') }}</div>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
|
|
|
<el-form-item label="API Token">
|
|
<el-form-item label="API Token">
|
|
@@ -23,20 +23,20 @@
|
|
|
show-password
|
|
show-password
|
|
|
/>
|
|
/>
|
|
|
<div class="form-tip">
|
|
<div class="form-tip">
|
|
|
- 仅在前端直接调用 API 时需要(不推荐)
|
|
|
|
|
|
|
+ {{ t('仅在前端直接调用 API 时需要(不推荐)') }}
|
|
|
<br />
|
|
<br />
|
|
|
- 推荐通过后端代理调用,避免暴露 Token
|
|
|
|
|
|
|
+ {{ t('推荐通过后端代理调用,避免暴露 Token') }}
|
|
|
</div>
|
|
</div>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
|
|
|
<el-form-item>
|
|
<el-form-item>
|
|
|
- <el-button type="primary" @click="saveConfig">保存配置</el-button>
|
|
|
|
|
- <el-button @click="testConnection">测试连接</el-button>
|
|
|
|
|
|
|
+ <el-button type="primary" @click="saveConfig">{{ t('保存配置') }}</el-button>
|
|
|
|
|
+ <el-button @click="testConnection">{{ t('测试连接') }}</el-button>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-form>
|
|
</el-form>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
|
|
|
|
|
- <el-card header="配置说明" style="margin-top: 20px">
|
|
|
|
|
|
|
+ <el-card :header="t('配置说明')" style="margin-top: 20px">
|
|
|
<el-collapse>
|
|
<el-collapse>
|
|
|
<el-collapse-item title="如何获取 Account ID" name="1">
|
|
<el-collapse-item title="如何获取 Account ID" name="1">
|
|
|
<ol>
|
|
<ol>
|
|
@@ -49,7 +49,7 @@
|
|
|
</ol>
|
|
</ol>
|
|
|
</el-collapse-item>
|
|
</el-collapse-item>
|
|
|
|
|
|
|
|
- <el-collapse-item title="如何获取 Customer Subdomain" name="2">
|
|
|
|
|
|
|
+ <el-collapse-item :title="t('如何获取 Customer Subdomain')" name="2">
|
|
|
<ol>
|
|
<ol>
|
|
|
<li>进入 Stream 产品页面</li>
|
|
<li>进入 Stream 产品页面</li>
|
|
|
<li>上传或选择任意视频</li>
|
|
<li>上传或选择任意视频</li>
|
|
@@ -80,54 +80,16 @@
|
|
|
</el-alert>
|
|
</el-alert>
|
|
|
</el-collapse-item>
|
|
</el-collapse-item>
|
|
|
|
|
|
|
|
- <el-collapse-item title="后端 API 代理示例" name="4">
|
|
|
|
|
- <pre class="code-block">
|
|
|
|
|
-// Node.js / Express 示例
|
|
|
|
|
-const express = require('express');
|
|
|
|
|
-const axios = require('axios');
|
|
|
|
|
-
|
|
|
|
|
-const CLOUDFLARE_ACCOUNT_ID = process.env.CF_ACCOUNT_ID;
|
|
|
|
|
-const CLOUDFLARE_API_TOKEN = process.env.CF_API_TOKEN;
|
|
|
|
|
-
|
|
|
|
|
-const cfApi = axios.create({
|
|
|
|
|
- baseURL: `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/stream`,
|
|
|
|
|
- headers: {
|
|
|
|
|
- 'Authorization': `Bearer ${CLOUDFLARE_API_TOKEN}`,
|
|
|
|
|
- 'Content-Type': 'application/json'
|
|
|
|
|
- }
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// 获取视频列表
|
|
|
|
|
-app.get('/api/stream/video/list', async (req, res) => {
|
|
|
|
|
- const response = await cfApi.get('/');
|
|
|
|
|
- res.json({
|
|
|
|
|
- code: 200,
|
|
|
|
|
- data: {
|
|
|
|
|
- rows: response.data.result,
|
|
|
|
|
- total: response.data.result.length
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// 创建直播输入
|
|
|
|
|
-app.post('/api/stream/live', async (req, res) => {
|
|
|
|
|
- const response = await cfApi.post('/live_inputs', req.body);
|
|
|
|
|
- res.json({
|
|
|
|
|
- code: 200,
|
|
|
|
|
- data: response.data.result
|
|
|
|
|
- });
|
|
|
|
|
-});</pre
|
|
|
|
|
- >
|
|
|
|
|
- </el-collapse-item>
|
|
|
|
|
|
|
+ <el-collapse-item title="后端 API 代理示例" name="4"></el-collapse-item>
|
|
|
</el-collapse>
|
|
</el-collapse>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
|
|
|
|
|
- <el-card header="快速测试" style="margin-top: 20px">
|
|
|
|
|
|
|
+ <el-card :header="t('快速测试')" style="margin-top: 20px">
|
|
|
<el-form label-width="100px" style="max-width: 800px">
|
|
<el-form label-width="100px" style="max-width: 800px">
|
|
|
<el-form-item label="Video ID">
|
|
<el-form-item label="Video ID">
|
|
|
<el-input v-model="testVideoId" placeholder="输入 Video ID 测试播放" style="width: 400px" />
|
|
<el-input v-model="testVideoId" placeholder="输入 Video ID 测试播放" style="width: 400px" />
|
|
|
<el-button type="primary" style="margin-left: 10px" @click="testPlay" :disabled="!testVideoId">
|
|
<el-button type="primary" style="margin-left: 10px" @click="testPlay" :disabled="!testVideoId">
|
|
|
- 测试播放
|
|
|
|
|
|
|
+ {{ t('测试播放') }}
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
|
|
@@ -136,17 +98,17 @@ app.post('/api/stream/live', async (req, res) => {
|
|
|
<div class="url-item">
|
|
<div class="url-item">
|
|
|
<span class="label">HLS:</span>
|
|
<span class="label">HLS:</span>
|
|
|
<code>{{ testHlsUrl }}</code>
|
|
<code>{{ testHlsUrl }}</code>
|
|
|
- <el-button link type="primary" @click="copyUrl(testHlsUrl)">复制</el-button>
|
|
|
|
|
|
|
+ <el-button link type="primary" @click="copyUrl(testHlsUrl)">{{ t('复制') }}</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="url-item">
|
|
<div class="url-item">
|
|
|
<span class="label">DASH:</span>
|
|
<span class="label">DASH:</span>
|
|
|
<code>{{ testDashUrl }}</code>
|
|
<code>{{ testDashUrl }}</code>
|
|
|
- <el-button link type="primary" @click="copyUrl(testDashUrl)">复制</el-button>
|
|
|
|
|
|
|
+ <el-button link type="primary" @click="copyUrl(testDashUrl)">{{ t('复制') }}</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="url-item">
|
|
<div class="url-item">
|
|
|
<span class="label">iframe:</span>
|
|
<span class="label">iframe:</span>
|
|
|
<code>{{ testIframeUrl }}</code>
|
|
<code>{{ testIframeUrl }}</code>
|
|
|
- <el-button link type="primary" @click="copyUrl(testIframeUrl)">复制</el-button>
|
|
|
|
|
|
|
+ <el-button link type="primary" @click="copyUrl(testIframeUrl)">{{ t('复制') }}</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
@@ -154,7 +116,7 @@ app.post('/api/stream/live', async (req, res) => {
|
|
|
</el-card>
|
|
</el-card>
|
|
|
|
|
|
|
|
<!-- 测试播放弹窗 -->
|
|
<!-- 测试播放弹窗 -->
|
|
|
- <el-dialog v-model="playDialogVisible" title="测试播放" width="900px" destroy-on-close>
|
|
|
|
|
|
|
+ <el-dialog v-model="playDialogVisible" :title="t('测试播放')" width="900px" destroy-on-close>
|
|
|
<div class="player-container">
|
|
<div class="player-container">
|
|
|
<VideoPlayer
|
|
<VideoPlayer
|
|
|
v-if="playDialogVisible && testVideoId"
|
|
v-if="playDialogVisible && testVideoId"
|
|
@@ -173,6 +135,9 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
import { ElMessage } from 'element-plus'
|
|
|
import VideoPlayer from '@/components/VideoPlayer.vue'
|
|
import VideoPlayer from '@/components/VideoPlayer.vue'
|
|
|
import { useStreamStore } from '@/store/stream'
|
|
import { useStreamStore } from '@/store/stream'
|
|
|
|
|
+import { useI18n } from 'vue-i18n'
|
|
|
|
|
+
|
|
|
|
|
+const { t } = useI18n()
|
|
|
|
|
|
|
|
const streamStore = useStreamStore()
|
|
const streamStore = useStreamStore()
|
|
|
|
|
|