reorder args, update config, fix channel add/update, fix #786
This commit is contained in:
parent
7b27dcd12b
commit
a35e75331c
@ -3,6 +3,8 @@ members = ["engine", "tests"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
description = "24/7 playout based on rust and ffmpeg"
|
||||
readme = "README.md"
|
||||
version = "0.24.0-beta5"
|
||||
license = "GPL-3.0"
|
||||
repository = "https://github.com/ffplayout/ffplayout"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "ffplayout"
|
||||
description = "24/7 playout based on rust and ffmpeg"
|
||||
readme = "../README.md"
|
||||
description.workspace = true
|
||||
readme.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
@ -35,7 +35,9 @@ Stream dynamic playlists or folder contents with the power of ffmpeg.
|
||||
The target can be an HLS playlist, rtmp/srt/udp server, desktop player
|
||||
or any other output supported by ffmpeg.\n
|
||||
ffplayout also provides a web frontend and API to control streaming,
|
||||
manage config, files, text overlay, etc. "))]
|
||||
manage config, files, text overlay, etc."),
|
||||
next_line_help = false,
|
||||
)]
|
||||
pub struct Args {
|
||||
#[clap(
|
||||
short,
|
||||
@ -45,9 +47,6 @@ pub struct Args {
|
||||
)]
|
||||
pub init: bool,
|
||||
|
||||
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Add a global admin")]
|
||||
pub add: bool,
|
||||
|
||||
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Create admin user")]
|
||||
pub username: Option<String>,
|
||||
|
||||
@ -77,6 +76,9 @@ pub struct Args {
|
||||
#[clap(long, help_heading = Some("Initial Setup / Playlist"), help = "Path to playlist, or playlist root folder.")]
|
||||
pub playlists: Option<String>,
|
||||
|
||||
#[clap(short, long, help_heading = Some("General"), help = "Add a global admin")]
|
||||
pub add: bool,
|
||||
|
||||
#[clap(long, env, help_heading = Some("General"), help = "Path to database file")]
|
||||
pub db: Option<PathBuf>,
|
||||
|
||||
@ -360,7 +362,6 @@ pub async fn run_args(pool: &Pool<Sqlite>) -> Result<(), i32> {
|
||||
if global.shared {
|
||||
storage_path = storage_path.join("1");
|
||||
|
||||
channel.preview_url = "http://127.0.0.1:8787/1/stream.m3u8".to_string();
|
||||
channel.public = Path::new(&channel.public)
|
||||
.join("1")
|
||||
.to_string_lossy()
|
||||
|
@ -11,21 +11,37 @@
|
||||
<div class="label">
|
||||
<span class="label-text">{{ t('config.name') }}</span>
|
||||
</div>
|
||||
<input v-model="channel.name" type="text" placeholder="Type here" class="input input-bordered w-full" />
|
||||
<input
|
||||
v-model="channel.name"
|
||||
type="text"
|
||||
placeholder="Type here"
|
||||
class="input input-bordered w-full"
|
||||
@keyup="isChanged"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="form-control w-full mt-5">
|
||||
<div class="label">
|
||||
<span class="label-text">{{ t('config.previewUrl') }}</span>
|
||||
</div>
|
||||
<input v-model="channel.preview_url" type="text" class="input input-bordered w-full" />
|
||||
<input
|
||||
v-model="channel.preview_url"
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
@keyup="isChanged"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="form-control w-full mt-5">
|
||||
<div class="label">
|
||||
<span class="label-text">{{ t('config.extensions') }}</span>
|
||||
</div>
|
||||
<input v-model="channel.extra_extensions" type="text" class="input input-bordered w-full" />
|
||||
<input
|
||||
v-model="channel.extra_extensions"
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
@keyup="isChanged"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<template v-if="authStore.role === 'GlobalAdmin'">
|
||||
@ -39,21 +55,36 @@
|
||||
<div class="label">
|
||||
<span class="label-text">{{ t('config.publicPath') }}</span>
|
||||
</div>
|
||||
<input v-model="channel.public" type="text" class="input input-bordered w-full" />
|
||||
<input
|
||||
v-model="channel.public"
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
@keyup="isChanged"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="form-control w-full mt-5">
|
||||
<div class="label">
|
||||
<span class="label-text">{{ t('config.playlistPath') }}</span>
|
||||
</div>
|
||||
<input v-model="channel.playlists" type="text" class="input input-bordered w-full" />
|
||||
<input
|
||||
v-model="channel.playlists"
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
@keyup="isChanged"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label class="form-control w-full mt-5">
|
||||
<div class="label">
|
||||
<span class="label-text">{{ t('config.storagePath') }}</span>
|
||||
</div>
|
||||
<input v-model="channel.storage" type="text" class="input input-bordered w-full" />
|
||||
<input
|
||||
v-model="channel.storage"
|
||||
type="text"
|
||||
class="input input-bordered w-full"
|
||||
@keyup="isChanged"
|
||||
/>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
@ -62,7 +93,9 @@
|
||||
{{ t('config.save') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="authStore.role === 'GlobalAdmin' && configStore.channels.length > 1 && channel.id > 1 && saved"
|
||||
v-if="
|
||||
authStore.role === 'GlobalAdmin' && configStore.channels.length > 1 && channel.id > 1 && saved
|
||||
"
|
||||
class="btn btn-primary"
|
||||
@click="deleteChannel()"
|
||||
>
|
||||
@ -77,7 +110,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { cloneDeep, isEqual } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -88,9 +121,11 @@ const { i } = storeToRefs(useConfig())
|
||||
|
||||
const saved = ref(true)
|
||||
const channel = ref({} as Channel)
|
||||
const channelOrig = ref({} as Channel)
|
||||
|
||||
onMounted(() => {
|
||||
channel.value = cloneDeep(configStore.channels[i.value])
|
||||
channelOrig.value = cloneDeep(configStore.channels[i.value])
|
||||
})
|
||||
|
||||
watch([i], () => {
|
||||
@ -99,6 +134,14 @@ watch([i], () => {
|
||||
}
|
||||
})
|
||||
|
||||
function isChanged() {
|
||||
if (isEqual(channel.value, channelOrig.value)) {
|
||||
saved.value = true
|
||||
} else {
|
||||
saved.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function rmId(path: string) {
|
||||
return path.replace(/\/\d+$/, '')
|
||||
}
|
||||
@ -114,23 +157,68 @@ function newChannel() {
|
||||
saved.value = false
|
||||
}
|
||||
|
||||
async function addNewChannel() {
|
||||
await $fetch('/api/channel/', {
|
||||
method: 'POST',
|
||||
headers: { ...configStore.contentType, ...authStore.authHeader },
|
||||
body: JSON.stringify(channel.value),
|
||||
})
|
||||
.then((chl) => {
|
||||
i.value = channel.value.id - 1
|
||||
configStore.channels.push(cloneDeep(chl))
|
||||
configStore.channelsRaw.push(chl)
|
||||
configStore.configCount = configStore.channels.length
|
||||
|
||||
indexStore.msgAlert('success', t('config.updateChannelSuccess'), 2)
|
||||
})
|
||||
.catch(() => {
|
||||
indexStore.msgAlert('error', t('config.updateChannelFailed'), 3)
|
||||
})
|
||||
}
|
||||
|
||||
async function updateChannel() {
|
||||
await fetch(`/api/channel/${channel.value.id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { ...configStore.contentType, ...authStore.authHeader },
|
||||
body: JSON.stringify(channel.value),
|
||||
})
|
||||
.then(() => {
|
||||
for (let i = 0; i < configStore.channels.length; i++) {
|
||||
if (configStore.channels[i].id === channel.value.id) {
|
||||
configStore.channels[i] = cloneDeep(channel.value)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < configStore.channelsRaw.length; i++) {
|
||||
if (configStore.channelsRaw[i].id === channel.value.id) {
|
||||
configStore.channelsRaw[i] = cloneDeep(channel.value)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
indexStore.msgAlert('success', t('config.updateChannelSuccess'), 2)
|
||||
})
|
||||
.catch(() => {
|
||||
indexStore.msgAlert('error', t('config.updateChannelFailed'), 3)
|
||||
})
|
||||
}
|
||||
|
||||
async function addUpdateChannel() {
|
||||
/*
|
||||
Save channel settings.
|
||||
Save or update channel settings.
|
||||
*/
|
||||
saved.value = true
|
||||
i.value = channel.value.id - 1
|
||||
configStore.channels.push(cloneDeep(channel.value))
|
||||
const update = await configStore.setChannelConfig(channel.value)
|
||||
if (!saved.value) {
|
||||
saved.value = true
|
||||
|
||||
if (update.status && update.status < 400) {
|
||||
indexStore.msgAlert('success', t('config.updateChannelSuccess'), 2)
|
||||
if (configStore.channels[i.value].id !== channel.value.id) {
|
||||
await addNewChannel()
|
||||
} else {
|
||||
await updateChannel()
|
||||
}
|
||||
|
||||
await configStore.getPlayoutConfig()
|
||||
await configStore.getUserConfig()
|
||||
|
||||
} else {
|
||||
indexStore.msgAlert('error', t('config.updateChannelFailed'), 2)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,45 +95,6 @@ export const useConfig = defineStore('config', {
|
||||
})
|
||||
},
|
||||
|
||||
async setChannelConfig(obj: Channel): Promise<any> {
|
||||
const authStore = useAuth()
|
||||
const stringObj = cloneDeep(obj)
|
||||
let response
|
||||
|
||||
if (this.channelsRaw.some((e) => e.id === stringObj.id)) {
|
||||
response = await fetch(`/api/channel/${obj.id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { ...this.contentType, ...authStore.authHeader },
|
||||
body: JSON.stringify(stringObj),
|
||||
})
|
||||
} else {
|
||||
response = await fetch('/api/channel/', {
|
||||
method: 'POST',
|
||||
headers: { ...this.contentType, ...authStore.authHeader },
|
||||
body: JSON.stringify(stringObj),
|
||||
})
|
||||
|
||||
const json = await response.json()
|
||||
const channelConfigs = []
|
||||
|
||||
for (const obj of this.channels) {
|
||||
if (obj.name === stringObj.name) {
|
||||
channelConfigs.push(json)
|
||||
} else {
|
||||
channelConfigs.push(obj)
|
||||
}
|
||||
}
|
||||
|
||||
this.channels = channelConfigs
|
||||
this.channelsRaw = cloneDeep(channelConfigs)
|
||||
this.configCount = channelConfigs.length
|
||||
}
|
||||
|
||||
await this.getPlayoutConfig()
|
||||
|
||||
return response
|
||||
},
|
||||
|
||||
async getPlayoutConfig() {
|
||||
const { $i18n } = useNuxtApp()
|
||||
const { timeToSeconds } = stringFormatter()
|
||||
|
Loading…
Reference in New Issue
Block a user