Commit c7731fcb by haojie

洗稿

parent 0d8701a5
......@@ -25,6 +25,7 @@
"rules": {
// 禁止 || true ,关闭
"no-constant-condition": 0,
"no-empty": 0,
"vue/no-setup-props-destructure": 0,
"vue/no-v-model-argument": 0,
"vue/no-v-for-template-key": 0,
......
......@@ -6,9 +6,10 @@
:volume="firstVideoVolume"
ref="videoFirst"
class="video-default"
loop
:src="video1"
:loop="loop"
@canplay="canplay"
@ended="firstVideoEnded"
></video>
<video
v-show="!showFirstVideo"
......@@ -16,7 +17,7 @@
:volume="secondVideoVolume"
class="video-default"
:src="video2"
@ended="onVideoEnded"
@ended="secondVideoEnded"
@canplay="canplay2"
></video>
<ConfirmDialog v-model="confirmVisible" :closeOnOverlayClick="false" :footer="footerStatus" @confirm="confirm">
......@@ -42,19 +43,35 @@ import { onBeforeRouteLeave } from 'vue-router';
import { injectWindow } from '@/utils/pyqt';
import { show_message } from '@/utils/tool';
const props = defineProps<{
video1: string;
video2: string;
playId?: any;
progress: number;
}>();
const props = withDefaults(
defineProps<{
video1: string;
video2: string;
playId?: any;
progress: number;
mainIndex?: number | null;
totalTime: number;
liveDetail: any;
}>(),
{
mainIndex: null,
},
);
const emit = defineEmits(['playEnd', 'update:progress']);
const emit = defineEmits([
'update:totalTime',
'currentTime',
'playEnd',
'mainVideoStartPlay',
'mainVideoPlayEnd',
'update:progress',
]);
const store = useStore();
const videoNum = computed(() => store.getters['live/getVideoNum']);
const liveVideoStatus = computed(() => store.getters['live/getLiveVideoStatus']);
const loop = ref(false);
const loading = ref(true);
const footerStatus = ref(false);
const showFirstVideo = ref(true);
......@@ -63,6 +80,9 @@ const videoSecondPlay = ref(false);
const confirmVisible = ref(true);
// 第一个视频是否首次播放
const videoFirstPlay = ref(true);
// 第二个视频是否首次播放
const videoSecondFirstPlay = ref(true);
......@@ -98,18 +118,35 @@ const closeInterval = () => {
interval = null;
};
// 确定播放
const confirm = () => {
openInterval();
onPlay();
videoFirstPlay.value = false;
emit('mainVideoStartPlay', props.mainIndex);
};
// 主视频可以播放
const canplay = () => {
// 获取视频总时长
total.value = videoFirst.value.duration;
// onPlay();
emit('update:totalTime', total.value);
if (!videoFirstPlay.value) {
//
onPlay();
emit('mainVideoStartPlay', props.mainIndex);
}
};
// 主视频播放完毕
const firstVideoEnded = () => {
if (videoFirst.value.ended) {
emit('mainVideoPlayEnd', props.mainIndex);
}
};
const onVideoEnded = () => {
// 互动视频播放完毕
const secondVideoEnded = () => {
if (videoSecond.value?.ended) {
emit('playEnd', props.playId);
showFirstVideo.value = true;
......@@ -156,6 +193,17 @@ watch(
},
);
// 判断是否洗稿
watch(
() => props.liveDetail,
(v) => {
if (v && v.is_disorganize === 0) {
// 不洗稿,开启循环播放
loop.value = true;
}
},
);
watch(
() => props.video1,
(v) => {
......@@ -183,6 +231,8 @@ const updateTime = () => {
if (total.value) {
// 计算百分比
emit('update:progress', Math.floor((videoFirst.value.currentTime / total.value) * 100));
// 提交当前进度
emit('currentTime', videoFirst.value.currentTime);
}
};
// 减小正在播放的视频音量
......
......@@ -102,19 +102,21 @@ export default defineComponent({
// 文件是否上传过
const fileHasUploaded = (file: File) => {
for (let i = 0; i < fileList.value.length; i++) {
let item = fileList.value[i].file;
if (
item === file ||
(item.lastModified == file.lastModified &&
item.name == file.name &&
item.size == file.size &&
item.type == file.type)
) {
show_message(`${file.name}已经上传过了`);
return false;
}
}
// for (let i = 0; i < fileList.value.length; i++) {
// let item = fileList.value[i].file;
// if (item) {
// if (
// item === file ||
// (item.lastModified == file.lastModified &&
// item.name == file.name &&
// item.size == file.size &&
// item.type == file.type)
// ) {
// show_message(`${file.name}已经上传过了`);
// return false;
// }
// }
// }
return true;
};
......@@ -131,9 +133,11 @@ export default defineComponent({
return false;
}
// 文件后缀
const fileSuffix = getFileSuffix(file);
let fileSuffix = getFileSuffix(file);
if (props.accept) {
if (props.accept.indexOf(fileSuffix) == -1) {
let accept = props.accept.toLowerCase();
fileSuffix = fileSuffix.toLowerCase();
if (accept.indexOf(fileSuffix) == -1) {
show_message(`本次上传仅支持${props.accept}格式`);
return false;
}
......@@ -269,6 +273,8 @@ export default defineComponent({
fileList.value.forEach((item: any) => {
if (item.url) {
list.push(item.url);
} else if (item.audio_url) {
list.push(item.audio_url);
}
if (item.time) {
totalTime += item.time;
......@@ -322,7 +328,7 @@ export default defineComponent({
</span>
</div>
)}
<div class="file-name">{item.file.name}</div>
<div class="file-name">{item.file?.name}</div>
{computedTotalTime() ? (
<audio
src={item.url}
......
......@@ -15,6 +15,7 @@
</template>
<script lang="ts" setup>
import allRouter from '@/router';
import { useRoute } from 'vue-router';
const route = useRoute();
......
<template>
<div class="start-only-video-live">
<!-- <Button theme="green" @click="playVideo">开始播放</Button> -->
<AddVideoPlay
v-model:progress="progress"
:playId="playId"
@playEnd="playEnd"
:video1="video"
:video2="video2"
></AddVideoPlay>
</div>
</template>
<script lang="ts" setup>
import Button from '@/components/Button.vue';
import { onBeforeUnmount, ref, watch } from 'vue';
import AddVideoPlay from '@/components/AddVideoPlay.vue';
const props = withDefaults(
defineProps<{
video: any;
video2: any;
playId?: any;
modelValue: any;
}>(),
{
playId: 0,
},
);
const videoRef1 = ref<HTMLVideoElement>();
let interval1 = null;
const progress = ref(0);
const emit = defineEmits(['update:modelValue', 'playEnd']);
watch(
() => progress.value,
(v) => {
emit('update:modelValue', v);
},
);
const playEnd = (id: any) => {
emit('playEnd', id);
};
const closeInterval = () => {
window.clearInterval(interval1);
clearInterval(interval1);
interval1 = null;
};
const playVideo = () => {
console.log(videoRef1.value);
videoRef1.value.play();
closeInterval();
interval1 = window.setInterval(() => {
// 播放结束
if (videoRef1.value.ended) {
closeInterval();
}
}, 100);
};
onBeforeUnmount(() => {
closeInterval();
});
</script>
<style lang="less">
.start-only-video-live {
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
</style>
......@@ -12,7 +12,7 @@
maxHeight: maxHeight + 'px',
}"
>
<Grid :length="digitalList.list.length" :rowGap="12" :marginLeft="8">
<div class="create-digital-person-grid">
<template v-for="item in digitalList.list" :key="item.id">
<CardOne
:row="item"
......@@ -23,7 +23,7 @@
@change="onCardChange"
></CardOne>
</template>
</Grid>
</div>
</div>
</div>
</div>
......@@ -31,10 +31,9 @@
<script lang="ts" setup>
import Loading from '@/components/loading.vue';
import Grid from '@/components/Grid.vue';
import Select from '@/components/Select.vue';
import CardOne from '@/components/cardOne.vue';
import { ref, onMounted, reactive, watch, computed } from 'vue';
import { ref, onMounted, reactive, watch, computed, onActivated } from 'vue';
import { getElBounding, getWindowClient, isDev } from '@/utils/tool';
import { useStore } from 'vuex';
import { createLiveKeys } from '@/service/CreateLive';
......@@ -84,12 +83,14 @@ const updateInfo = (info: any) => {
name = info.name;
digital_man_id = info.digital_man_id;
} else if (info.content) {
// 草稿
name = info.content.name ? info.content.name : '';
digital_man_id = info.content.digital_man_id ? info.content.digital_man_id : '';
}
// 更新标题
store.commit('live/setName', name);
if (name) {
// 更新标题
store.commit('live/setName', name);
}
if (info.users_id !== 0) {
// 我的数字人
currentOption.value = '2';
......@@ -122,11 +123,13 @@ watch(
);
const onSelectChange = (value: string) => {
commitInfo({
[createLiveKeys.id_type]: value,
});
currentOption.value = value;
checkPerson();
if (value) {
commitInfo({
[createLiveKeys.id_type]: value,
});
currentOption.value = value;
checkPerson();
}
};
// 从python获取视频路径
......@@ -158,6 +161,26 @@ const digitalList = reactive({
my: [],
});
const findIdinList = () => {
if (route.query.id) {
// 找到对应的id
let index1 = digitalList.my.findIndex((item: any) => item.id == route.query.id);
if (index1 !== -1) {
currentCard.value = digitalList.my[index1].id;
}
let index2 = digitalList.admin.findIndex((item: any) => item.id == route.query.id);
if (index2 !== -1) {
currentCard.value = digitalList.admin[index2].id;
}
if (currentCard.value) {
let params = {
[createLiveKeys.id]: currentCard.value,
};
commitInfo(params);
}
}
};
const changeCurrentList = () => {
if (currentCard.value) {
// 找到对应的库
......@@ -189,6 +212,7 @@ const getList = async () => {
digitalList.admin = res.adminList;
// digitalList.admin = digitalList.admin.concat(res.adminList);
digitalList.my = res.myList;
findIdinList();
changeCurrentList();
checkPerson();
loading.value = false;
......@@ -196,15 +220,18 @@ const getList = async () => {
loading.value = false;
console.log(e);
}
// 提交默认参数
if (currentOption.value) {
let params = {
[createLiveKeys.id_type]: currentOption.value,
};
commitInfo(params);
}
};
onMounted(() => {
onActivated(() => {
// 获取数字人列表
getList();
// 提交默认参数
commitInfo({
[createLiveKeys.id_type]: currentOption.value,
});
});
watch(
......@@ -250,6 +277,12 @@ watch(
height: 150px;
}
}
.create-digital-person-grid {
display: grid;
justify-content: space-between;
grid-template-columns: repeat(auto-fill, 150px);
grid-gap: 12px;
}
.card-active {
border: 2px solid #00dfb0;
}
......
......@@ -2,7 +2,9 @@
<div class="create-live-script-setting">
<div class="all-select">
<Select :options="scriptTypeList" v-model="currentOption" @change="scriptTypeChange"></Select>
<CheckBox v-model="isDisorganize" @change="checkboxChange">GPT洗稿</CheckBox>
<template v-if="currentOption == scriptTypeText">
<CheckBox v-model="isDisorganize" @change="checkboxChange">GPT洗稿</CheckBox>
</template>
<template v-if="isDev()">
<Button
@click="
......@@ -152,6 +154,7 @@
v-model="item.data"
:config="ossConfig"
label="选择音频"
accept="wav"
@change="uploadEdit"
></MultipleUpload>
</div>
......@@ -191,7 +194,7 @@
</template>
<script lang="tsx" setup>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { computed, onActivated, onMounted, reactive, ref, watch } from 'vue';
import Button from '@/components/Button.vue';
import MultipleUpload from '@/components/MultipleUpload';
import CheckBox from '@/components/CheckBox.vue';
......@@ -423,42 +426,60 @@ const updateTonesInfo = (tone_id: any, phonetic_timbres_id: any) => {
};
const updateInfo = (info: any) => {
let type = '';
let type_content = '';
let phonetic_timbres_id = '';
let tone_id = '';
if (route.query.type == 'edit') {
type = info.type;
type_content = info.type_content;
phonetic_timbres_id = info.phonetic_timbres_id;
tone_id = info.tone_id;
} else if (info.content) {
type = info.content.type;
type_content = info.content.type_content;
phonetic_timbres_id = info.content.phonetic_timbres_id ? info.content.phonetic_timbres_id : '';
tone_id = info.content.tone_id ? info.content.tone_id : '';
}
// 脚本类型
if (type == scriptTypeText) {
// 文本
currentOption.value = scriptTypeText;
// 内容
textareaValue.value = type_content;
} else {
// 音频
currentOption.value = scriptTypePhonetics;
mp3Url.value = type_content;
if (Object.keys(info).length) {
let type = '';
let type_content = '';
let phonetic_timbres_id = '';
let tone_id = '';
if (route.query.type == 'edit') {
type = info.type;
type_content = info.type_content;
phonetic_timbres_id = info.phonetic_timbres_id;
tone_id = info.tone_id;
} else if (info.content) {
// 草稿
type = info.content.type;
type_content = info.content.type_content;
phonetic_timbres_id = info.content.phonetic_timbres_id ? info.content.phonetic_timbres_id : '';
tone_id = info.content.tone_id ? info.content.tone_id : '';
}
// 脚本类型
if (type == scriptTypeText) {
// 文本
currentOption.value = scriptTypeText;
if (type_content) {
// 内容
// textareaValue.value = type_content;
textScriptList.value = type_content;
}
// 洗稿
isDisorganize.value = info.is_disorganize ? true : false;
} else {
// 音频
currentOption.value = scriptTypePhonetics;
// mp3Url.value = type_content;
if (type_content) {
audioScriptList.value = type_content.map((item: any) => {
return {
data: item,
};
});
} else {
audioScriptList.value = [];
}
if (phonetic_timbres_id) {
phoneticsValue.value = phonetic_timbres_id;
}
}
tonesValue.value = tone_id;
if (phonetic_timbres_id) {
phoneticsValue.value = phonetic_timbres_id;
soundColorValue.value = phonetic_timbres_id;
}
}
tonesValue.value = tone_id;
if (phonetic_timbres_id) {
soundColorValue.value = phonetic_timbres_id;
}
// 更新info
updateTonesInfo(tone_id, phonetic_timbres_id);
// 更新info
updateTonesInfo(tone_id, phonetic_timbres_id);
}
};
watch(
......@@ -483,10 +504,32 @@ watch(
phoneticsInfo.value = {};
textareaValue.value = '';
currentOption.value = scriptTypeText;
audioScriptList.value = [];
textScriptList.value = [];
scriptTypeChange(scriptTypeText + '');
},
);
watch(
() => soundColorValue.value,
(v) => {
if (!v) {
soundColorItemChange();
}
},
);
watch(
() => tonesValue.value,
(v) => {
if (v) {
disabled.value = false;
} else {
disabled.value = true;
}
},
);
const openSoundColor = () => {
if (tonesValue.value) {
// 允许打开
......@@ -526,15 +569,6 @@ const soundColorItemChange = (item: any = false) => {
}
};
watch(
() => soundColorValue.value,
(v) => {
if (!v) {
soundColorItemChange();
}
},
);
// 音频 音色提交
const phoneticsItemChange = (item: any) => {
phoneticsInfo.value = item;
......@@ -557,17 +591,6 @@ const scriptTypeChange = (id: string | number) => {
});
};
watch(
() => tonesValue.value,
(v) => {
if (v) {
disabled.value = false;
} else {
disabled.value = true;
}
},
);
const getList = async () => {
let res = await getTonesList();
lists.tones = res.tones;
......@@ -591,13 +614,18 @@ onMounted(async () => {
// 提交默认脚本类型
commitInfo({
[createLiveKeys.scriptType]: currentOption.value,
// 文本脚本的uuid
[createLiveKeys.scriptUuid]: getUuid(),
});
// 获取音色音调列表
getList();
});
onActivated(() => {
commitInfo({
// 文本脚本的uuid
[createLiveKeys.scriptUuid]: getUuid(),
});
});
</script>
<style lang="less">
......
......@@ -98,6 +98,7 @@ const confirm = () => {
query: {
id: currentCard.value,
title: '',
type: 'new',
},
});
};
......
......@@ -158,6 +158,7 @@ const dialogConfirm = () => {
query: {
id: currentCard.value,
title: liveName.value,
type: 'new',
},
});
};
......
......@@ -105,7 +105,7 @@ export const getLiveInteraction = async (select: boolean = false) => {
};
// 更新直播内容
export const onUpdateLiveTask = async (id: number | string, data: any) => {
export const onUpdateLiveTask = async (id: any, data: any) => {
try {
let res: any = await updateLiveTask(id, data);
if (res.code == 0) {
......
......@@ -11,3 +11,12 @@ export const LIVE_AUDIT_STATUS = {
LIVE_AUDIT_STATUS_FINISH: 3, // 己完成
LIVE_AUDIT_STATUS_ERROR: 4, // 审核失败
};
/**
* 洗稿状态(直播页面下一个视频是否准备完毕)
*/
export const CONFUSE_STATUS = {
CONFUSE_STATUS_WAIT: 1, // 未提交
CONFUSE_STATUS_PROGRESS: 2, // 进行中
CONFUSE_STATUS_SUCCESS: 3, // 已完成
};
......@@ -33,13 +33,18 @@ type StateType = typeof state;
const mutations = {
setName(state: StateType, info: string) {
state.name = info;
if (info) {
state.name = info;
} else {
state.name = '';
}
},
// 创建直播时的参数
setLiveInfo(state: StateType, info: any) {
Object.keys(info).forEach((item: any) => {
state.createLive[item] = info[item];
});
console.log(state.createLive);
},
initLiveInfo(state: StateType) {
state.createLive = initParams();
......
import routerConfig from '@/router/tool';
import { createLiveRouteKey } from '@/constants/token';
const imgs = {
home: new URL('../../assets/svg/home/home.svg', import.meta.url).href,
......@@ -43,6 +44,10 @@ const mutations = {
}
state.navbarList.push(info);
}
if (info.path == routerConfig.createLive.path) {
// 记录创建直播的参数
window.localStorage.setItem(createLiveRouteKey, JSON.stringify(info.query));
}
},
};
......
......@@ -361,9 +361,9 @@ export const liveContentRegenerateCallback = (data: any) => {
};
// 重新生成直播
export const liveTaskRegenerate = () => {
export const liveTaskRegenerate = (id: any, data: any) => {
const header = getHeader();
return request.post(`/api/live/task/{id}/regenerate`, '', {
return request.post(`/api/live/task/${id}/regenerate`, data, {
headers: {
...header,
},
......
......@@ -68,7 +68,6 @@ export async function audioMerge(filePaths) {
}
offset += Math.round(buffer.duration * sampleRate);
});
// 导出合并后的音频数据为 WAV 文件
const mergedData = exportBufferAsWav(mergedBuffer);
const blob = new Blob([mergedData], { type: 'audio/wav' });
......
import { show_message } from './tool';
class CustomException extends Error {
constructor(message) {
super(message);
this.name = 'CustomException';
show_message(message, 'error');
}
}
export default CustomException;
......@@ -263,3 +263,22 @@ export const downloadBlobFile = (blob: Blob, name: string = 'test') => {
// 清理 Blob URL
URL.revokeObjectURL(url);
};
// 二维数组转一维数组
export const dimensionalConvert = (list: any[]) => {
let convertList = [];
for (let i = 0; i < list.length; i++) {
let items = list[i];
if (DataType(items, 'array')) {
// 是数组
for (let j = 0; j < items.length; j++) {
let item = items[j];
convertList.push(item);
}
} else {
// 子元素不是数组,直接返回
return list;
}
}
return convertList;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment