revert ad color, fix path names, throttle buttons. work on channel creation
This commit is contained in:
parent
c3da356bc7
commit
64150a8262
@ -50,10 +50,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<label class="form-control w-full mt-3">
|
<label class="form-control w-full mt-3">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
<span class="label-text">{{ t('config.hlsPath') }}</span>
|
<span class="label-text">{{ t('config.publicPath') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
v-model="configStore.channels[configStore.id].hls_path"
|
v-model="configStore.channels[configStore.id].public"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-bordered w-full"
|
class="input input-bordered w-full"
|
||||||
/>
|
/>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
<span class="label-text">{{ t('config.playlistPath') }}</span>
|
<span class="label-text">{{ t('config.playlistPath') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
v-model="configStore.channels[configStore.id].playlist_path"
|
v-model="configStore.channels[configStore.id].playlists"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-bordered w-full"
|
class="input input-bordered w-full"
|
||||||
/>
|
/>
|
||||||
@ -75,7 +75,7 @@
|
|||||||
<span class="label-text">{{ t('config.storagePath') }}</span>
|
<span class="label-text">{{ t('config.storagePath') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
v-model="configStore.channels[configStore.id].storage_path"
|
v-model="configStore.channels[configStore.id].storage"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-bordered w-full"
|
class="input input-bordered w-full"
|
||||||
/>
|
/>
|
||||||
@ -83,7 +83,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="join my-4">
|
<div class="join my-4">
|
||||||
<button class="join-item btn btn-primary" @click="addUpdateChannel()">
|
<button class="join-item btn btn-primary" :class="saved ? 'btn-primary' : 'btn-error'" @click="addUpdateChannel()">
|
||||||
{{ t('config.save') }}
|
{{ t('config.save') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@ -103,31 +103,36 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { $_ } = useNuxtApp()
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const authStore = useAuth()
|
const authStore = useAuth()
|
||||||
const configStore = useConfig()
|
const configStore = useConfig()
|
||||||
const indexStore = useIndex()
|
const indexStore = useIndex()
|
||||||
|
|
||||||
|
const saved = ref(true)
|
||||||
|
|
||||||
function rmId(path: string) {
|
function rmId(path: string) {
|
||||||
return path.replace(/\/\d+$/, '')
|
return path.replace(/\/\d+$/, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
function newChannel() {
|
function newChannel() {
|
||||||
const channels = $_.cloneDeep(configStore.channels)
|
const channels = cloneDeep(configStore.channels)
|
||||||
const newChannel = $_.cloneDeep(configStore.channels[configStore.channels.length - 1])
|
const newChannel = cloneDeep(configStore.channels[configStore.channels.length - 1])
|
||||||
|
|
||||||
newChannel.id = channels.length + 1
|
newChannel.id = channels.length + 1
|
||||||
newChannel.name = `Channel ${newChannel.id}`
|
newChannel.name = `Channel ${newChannel.id}`
|
||||||
newChannel.preview_url = `${window.location.protocol}//${window.location.host}/${newChannel.id}/live/stream.m3u8`
|
newChannel.preview_url = `${window.location.protocol}//${window.location.host}/${newChannel.id}/live/stream.m3u8`
|
||||||
newChannel.hls_path = `${rmId(newChannel.hls_path)}/${newChannel.id}`
|
newChannel.public = `${rmId(newChannel.public)}/${newChannel.id}`
|
||||||
newChannel.playlist_path = `${rmId(newChannel.playlist_path)}/${newChannel.id}`
|
newChannel.playlists = `${rmId(newChannel.playlists)}/${newChannel.id}`
|
||||||
newChannel.storage_path = `${rmId(newChannel.storage_path)}/${newChannel.id}`
|
newChannel.storage = `${rmId(newChannel.storage)}/${newChannel.id}`
|
||||||
|
|
||||||
channels.push(newChannel)
|
channels.push(newChannel)
|
||||||
configStore.channels = channels
|
configStore.channels = channels
|
||||||
configStore.id = configStore.channels.length - 1
|
configStore.id = configStore.channels.length - 1
|
||||||
|
|
||||||
|
saved.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addUpdateChannel() {
|
async function addUpdateChannel() {
|
||||||
@ -138,13 +143,14 @@ async function addUpdateChannel() {
|
|||||||
|
|
||||||
if (update.status && update.status < 400) {
|
if (update.status && update.status < 400) {
|
||||||
indexStore.msgAlert('success', t('config.updateChannelSuccess'), 2)
|
indexStore.msgAlert('success', t('config.updateChannelSuccess'), 2)
|
||||||
|
saved.value = true
|
||||||
} else {
|
} else {
|
||||||
indexStore.msgAlert('error', t('config.updateChannelFailed'), 2)
|
indexStore.msgAlert('error', t('config.updateChannelFailed'), 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteChannel() {
|
async function deleteChannel() {
|
||||||
const config = $_.cloneDeep(configStore.channels)
|
const config = cloneDeep(configStore.channels)
|
||||||
const id = config[configStore.id].id
|
const id = config[configStore.id].id
|
||||||
|
|
||||||
if (id === 1) {
|
if (id === 1) {
|
||||||
|
@ -67,8 +67,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grow">
|
<div class="grow">
|
||||||
<strong>{{ t('player.duration') }}:</strong>
|
<strong>{{ t('player.duration') }}:</strong>
|
||||||
{{ secToHMS(playlistStore.current.duration) }} |
|
{{ secToHMS(playlistStore.current.duration) }} | <strong>{{ t('player.in') }}:</strong>
|
||||||
<strong>{{ t('player.in') }}:</strong> {{ secToHMS(playlistStore.current.in) }} |
|
{{ secToHMS(playlistStore.current.in) }} |
|
||||||
<strong>{{ t('player.out') }}:</strong>
|
<strong>{{ t('player.out') }}:</strong>
|
||||||
{{ secToHMS(playlistStore.current.out) }}
|
{{ secToHMS(playlistStore.current.out) }}
|
||||||
|
|
||||||
@ -80,7 +80,11 @@
|
|||||||
<div class="h-1/3">
|
<div class="h-1/3">
|
||||||
<progress
|
<progress
|
||||||
class="progress progress-accent w-full"
|
class="progress progress-accent w-full"
|
||||||
:value="playlistStore.progressValue"
|
:value="
|
||||||
|
playlistStore.progressValue && playlistStore.progressValue <= 100
|
||||||
|
? playlistStore.progressValue
|
||||||
|
: 0
|
||||||
|
"
|
||||||
max="100"
|
max="100"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -165,6 +169,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { throttle } from 'lodash-es'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import mpegts from 'mpegts.js'
|
import mpegts from 'mpegts.js'
|
||||||
|
|
||||||
@ -203,9 +208,7 @@ const mpegtsOptions = ref({
|
|||||||
liveBufferLatencyChasing: true,
|
liveBufferLatencyChasing: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const streamUrl = ref(
|
const streamUrl = ref(`/data/event/${configStore.channels[configStore.id].id}?endpoint=playout&uuid=${authStore.uuid}`)
|
||||||
`/data/event/${configStore.channels[configStore.id].id}?endpoint=playout&uuid=${authStore.uuid}`
|
|
||||||
)
|
|
||||||
|
|
||||||
// 'http://127.0.0.1:8787/data/event/1?endpoint=playout&uuid=f2f8c29b-712a-48c5-8919-b535d3a05a3a'
|
// 'http://127.0.0.1:8787/data/event/1?endpoint=playout&uuid=f2f8c29b-712a-48c5-8919-b535d3a05a3a'
|
||||||
const { status, data, error, close } = useEventSource(streamUrl, [], {
|
const { status, data, error, close } = useEventSource(streamUrl, [], {
|
||||||
@ -256,9 +259,9 @@ watch([status, error], async () => {
|
|||||||
|
|
||||||
if (errorCounter.value > 11) {
|
if (errorCounter.value > 11) {
|
||||||
await authStore.obtainUuid()
|
await authStore.obtainUuid()
|
||||||
streamUrl.value = `/data/event/${
|
streamUrl.value = `/data/event/${configStore.channels[configStore.id].id}?endpoint=playout&uuid=${
|
||||||
configStore.channels[configStore.id].id
|
authStore.uuid
|
||||||
}?endpoint=playout&uuid=${authStore.uuid}`
|
}`
|
||||||
errorCounter.value = 0
|
errorCounter.value = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,9 +283,7 @@ watch([data], () => {
|
|||||||
watch([id], () => {
|
watch([id], () => {
|
||||||
resetStatus()
|
resetStatus()
|
||||||
|
|
||||||
streamUrl.value = `/data/event/${configStore.channels[configStore.id].id}?endpoint=playout&uuid=${
|
streamUrl.value = `/data/event/${configStore.channels[configStore.id].id}?endpoint=playout&uuid=${authStore.uuid}`
|
||||||
authStore.uuid
|
|
||||||
}`
|
|
||||||
|
|
||||||
if (timer.value) {
|
if (timer.value) {
|
||||||
clearTimeout(timer.value)
|
clearTimeout(timer.value)
|
||||||
@ -313,20 +314,19 @@ function resetStatus() {
|
|||||||
playlistStore.current = currentDefault
|
playlistStore.current = currentDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
async function controlProcess(state: string) {
|
const controlProcess = throttle(async (state: string) => {
|
||||||
/*
|
/*
|
||||||
Control playout (start, stop, restart)
|
Control playout (start, stop, restart)
|
||||||
*/
|
*/
|
||||||
const channel = configStore.channels[configStore.id].id
|
const channel = configStore.channels[configStore.id].id
|
||||||
|
|
||||||
await $fetch(`/api/control/${channel}/process/`, {
|
await $fetch(`/api/control/${channel}/process/`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { ...configStore.contentType, ...authStore.authHeader },
|
headers: { ...configStore.contentType, ...authStore.authHeader },
|
||||||
body: JSON.stringify({ command: state }),
|
body: JSON.stringify({ command: state }),
|
||||||
})
|
})
|
||||||
}
|
}, 800)
|
||||||
|
|
||||||
async function controlPlayout(state: string) {
|
const controlPlayout = throttle(async (state: string) => {
|
||||||
/*
|
/*
|
||||||
Control playout:
|
Control playout:
|
||||||
- jump to next clip
|
- jump to next clip
|
||||||
@ -340,5 +340,5 @@ async function controlPlayout(state: string) {
|
|||||||
headers: { ...configStore.contentType, ...authStore.authHeader },
|
headers: { ...configStore.contentType, ...authStore.authHeader },
|
||||||
body: JSON.stringify({ control: state }),
|
body: JSON.stringify({ control: state }),
|
||||||
})
|
})
|
||||||
}
|
}, 800)
|
||||||
</script>
|
</script>
|
||||||
|
@ -347,7 +347,7 @@ function addFolderToTemplate(event: any, item: TemplateItem) {
|
|||||||
|
|
||||||
event.item.remove()
|
event.item.remove()
|
||||||
|
|
||||||
const storagePath = configStore.channels[configStore.id].storage_path
|
const storagePath = configStore.channels[configStore.id].storage
|
||||||
const navPath = mediaStore.folderCrumbs[mediaStore.folderCrumbs.length - 1].path
|
const navPath = mediaStore.folderCrumbs[mediaStore.folderCrumbs.length - 1].path
|
||||||
const sourcePath = `${storagePath}/${navPath}/${mediaStore.folderList.folders[o].name}`.replace(/\/[/]+/g, '/')
|
const sourcePath = `${storagePath}/${navPath}/${mediaStore.folderList.folders[o].name}`.replace(/\/[/]+/g, '/')
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
'!bg-lime-500/30':
|
'!bg-lime-500/30':
|
||||||
playlistStore.playoutIsRunning && listDate === todayDate && index === currentIndex,
|
playlistStore.playoutIsRunning && listDate === todayDate && index === currentIndex,
|
||||||
'!bg-amber-600/40': element.overtime,
|
'!bg-amber-600/40': element.overtime,
|
||||||
'text-blue-300': element.category === 'advertisement',
|
'text-base-content/60': element.category === 'advertisement',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<td v-if="!configStore.playout.playlist.infinit" class="ps-4 py-2 text-left">
|
<td v-if="!configStore.playout.playlist.infinit" class="ps-4 py-2 text-left">
|
||||||
@ -259,7 +259,7 @@ function addClip(event: any) {
|
|||||||
|
|
||||||
event.item?.remove()
|
event.item?.remove()
|
||||||
|
|
||||||
const storagePath = configStore.channels[configStore.id].storage_path
|
const storagePath = configStore.channels[configStore.id].storage
|
||||||
const sourcePath = `${storagePath}/${mediaStore.folderTree.source}/${mediaStore.folderTree.files[o].name}`.replace(
|
const sourcePath = `${storagePath}/${mediaStore.folderTree.source}/${mediaStore.folderTree.files[o].name}`.replace(
|
||||||
/\/[/]+/g,
|
/\/[/]+/g,
|
||||||
'/'
|
'/'
|
||||||
|
@ -200,7 +200,7 @@ export default {
|
|||||||
updatePlayoutFailed: 'Update playout config fehlgeschlagen!',
|
updatePlayoutFailed: 'Update playout config fehlgeschlagen!',
|
||||||
forbiddenPlaylistPath: 'Zugriff untersagt: Playlist-Ordner kann nicht geöffnet werden.',
|
forbiddenPlaylistPath: 'Zugriff untersagt: Playlist-Ordner kann nicht geöffnet werden.',
|
||||||
noPlayoutConfig: 'Keine Playout-Konfiguration gefunden!',
|
noPlayoutConfig: 'Keine Playout-Konfiguration gefunden!',
|
||||||
hlsPath: 'HLS-Pfad',
|
publicPath: 'Public (HLS) Pfad',
|
||||||
playlistPath: 'Wiedergabelistenpfad',
|
playlistPath: 'Wiedergabelistenpfad',
|
||||||
storagePath: 'Speicherpfad',
|
storagePath: 'Speicherpfad',
|
||||||
sharedStorage: 'Gemeinsamer Speicher ist aktiviert, verwende denselben Speicherstamm für alle Kanäle!',
|
sharedStorage: 'Gemeinsamer Speicher ist aktiviert, verwende denselben Speicherstamm für alle Kanäle!',
|
||||||
|
@ -199,7 +199,7 @@ export default {
|
|||||||
updatePlayoutFailed: 'Update playout config failed!',
|
updatePlayoutFailed: 'Update playout config failed!',
|
||||||
forbiddenPlaylistPath: 'Access forbidden: Playlist folder cannot be opened.',
|
forbiddenPlaylistPath: 'Access forbidden: Playlist folder cannot be opened.',
|
||||||
noPlayoutConfig: 'No playout config found!',
|
noPlayoutConfig: 'No playout config found!',
|
||||||
hlsPath: 'HLS Path',
|
publicPath: 'Public (HLS) Path',
|
||||||
playlistPath: 'Playlist Path',
|
playlistPath: 'Playlist Path',
|
||||||
storagePath: 'Storage Path',
|
storagePath: 'Storage Path',
|
||||||
sharedStorage: 'Shared storage is enabled, use the same storage root for all channels!',
|
sharedStorage: 'Shared storage is enabled, use the same storage root for all channels!',
|
||||||
|
@ -199,7 +199,7 @@ export default {
|
|||||||
updatePlayoutFailed: 'Falha na atualização da configuração do playout!',
|
updatePlayoutFailed: 'Falha na atualização da configuração do playout!',
|
||||||
forbiddenPlaylistPath: 'Acesso proibido: A pasta da lista de reprodução não pode ser aberta',
|
forbiddenPlaylistPath: 'Acesso proibido: A pasta da lista de reprodução não pode ser aberta',
|
||||||
noPlayoutConfig: 'Nenhuma configuração de playout encontrada!',
|
noPlayoutConfig: 'Nenhuma configuração de playout encontrada!',
|
||||||
hlsPath: 'HLS Path',
|
publicPath: 'Public (HLS) Path',
|
||||||
playlistPath: 'Playlist Path',
|
playlistPath: 'Playlist Path',
|
||||||
storagePath: 'Storage Path',
|
storagePath: 'Storage Path',
|
||||||
sharedStorage: 'O armazenamento compartilhado está ativado, use a mesma raiz de armazenamento para todos os canais',
|
sharedStorage: 'O armazenamento compartilhado está ativado, use a mesma raiz de armazenamento para todos os canais',
|
||||||
|
@ -199,7 +199,7 @@ export default {
|
|||||||
updatePlayoutFailed: 'Обновление конфигурации воспроизведения не удалось!',
|
updatePlayoutFailed: 'Обновление конфигурации воспроизведения не удалось!',
|
||||||
forbiddenPlaylistPath: 'Доступ запрещен: Папка плейлиста не может быть открыта.',
|
forbiddenPlaylistPath: 'Доступ запрещен: Папка плейлиста не может быть открыта.',
|
||||||
noPlayoutConfig: 'Конфигурация воспроизведения не найдена!',
|
noPlayoutConfig: 'Конфигурация воспроизведения не найдена!',
|
||||||
hlsPath: 'HLS Path',
|
publicPath: 'Public (HLS) Path',
|
||||||
playlistPath: 'Playlist Path',
|
playlistPath: 'Playlist Path',
|
||||||
storagePath: 'Storage Path',
|
storagePath: 'Storage Path',
|
||||||
sharedStorage: 'Общее хранилище включено, используйте один и тот же корень хранилища для всех каналов!',
|
sharedStorage: 'Общее хранилище включено, используйте один и тот же корень хранилища для всех каналов!',
|
||||||
|
20
frontend/package-lock.json
generated
20
frontend/package-lock.json
generated
@ -17,7 +17,7 @@
|
|||||||
"bootstrap-icons": "^1.11.3",
|
"bootstrap-icons": "^1.11.3",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mpegts.js": "^1.7.3",
|
"mpegts.js": "^1.7.3",
|
||||||
"nuxt": "3.13.2",
|
"nuxt": "3.13.2",
|
||||||
"pinia": "^2.2.2",
|
"pinia": "^2.2.2",
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"@nuxt/eslint": "^0.5.7",
|
"@nuxt/eslint": "^0.5.7",
|
||||||
"@nuxtjs/i18n": "^8.5.5",
|
"@nuxtjs/i18n": "^8.5.5",
|
||||||
"@nuxtjs/tailwindcss": "^6.12.1",
|
"@nuxtjs/tailwindcss": "^6.12.1",
|
||||||
"@types/lodash": "^4.17.9",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/video.js": "^7.3.58",
|
"@types/video.js": "^7.3.58",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
"mini-svg-data-uri": "^1.4.4",
|
"mini-svg-data-uri": "^1.4.4",
|
||||||
@ -3558,6 +3558,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/lodash-es": {
|
||||||
|
"version": "4.17.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
|
||||||
|
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/lodash": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.7.4",
|
"version": "22.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz",
|
||||||
@ -8988,6 +8998,12 @@
|
|||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.defaults": {
|
"node_modules/lodash.defaults": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
"bootstrap-icons": "^1.11.3",
|
"bootstrap-icons": "^1.11.3",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mpegts.js": "^1.7.3",
|
"mpegts.js": "^1.7.3",
|
||||||
"nuxt": "3.13.2",
|
"nuxt": "3.13.2",
|
||||||
"pinia": "^2.2.2",
|
"pinia": "^2.2.2",
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"@nuxt/eslint": "^0.5.7",
|
"@nuxt/eslint": "^0.5.7",
|
||||||
"@nuxtjs/i18n": "^8.5.5",
|
"@nuxtjs/i18n": "^8.5.5",
|
||||||
"@nuxtjs/tailwindcss": "^6.12.1",
|
"@nuxtjs/tailwindcss": "^6.12.1",
|
||||||
"@types/lodash": "^4.17.9",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/video.js": "^7.3.58",
|
"@types/video.js": "^7.3.58",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
"mini-svg-data-uri": "^1.4.4",
|
"mini-svg-data-uri": "^1.4.4",
|
||||||
|
@ -329,6 +329,7 @@ watch([width], () => {
|
|||||||
const horizontal = ref(false)
|
const horizontal = ref(false)
|
||||||
const deleteName = ref('')
|
const deleteName = ref('')
|
||||||
const renameOldName = ref('')
|
const renameOldName = ref('')
|
||||||
|
const renameOldPath = ref('')
|
||||||
const renameNewName = ref('')
|
const renameNewName = ref('')
|
||||||
const previewName = ref('')
|
const previewName = ref('')
|
||||||
const previewUrl = ref('')
|
const previewUrl = ref('')
|
||||||
@ -513,8 +514,13 @@ async function deleteFileOrFolder(del: boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setRenameValues(path: string) {
|
function setRenameValues(path: string) {
|
||||||
renameNewName.value = path
|
const index = path.lastIndexOf('/')
|
||||||
renameOldName.value = path
|
const dir = path.substring(0, index + 1) || '/'
|
||||||
|
const file = path.substring(index + 1)
|
||||||
|
|
||||||
|
renameOldName.value = file
|
||||||
|
renameOldPath.value = dir
|
||||||
|
renameNewName.value = file
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renameFile(ren: boolean) {
|
async function renameFile(ren: boolean) {
|
||||||
@ -527,7 +533,10 @@ async function renameFile(ren: boolean) {
|
|||||||
await fetch(`/api/file/${configStore.channels[configStore.id].id}/rename/`, {
|
await fetch(`/api/file/${configStore.channels[configStore.id].id}/rename/`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { ...configStore.contentType, ...authStore.authHeader },
|
headers: { ...configStore.contentType, ...authStore.authHeader },
|
||||||
body: JSON.stringify({ source: renameOldName.value, target: renameNewName.value }),
|
body: JSON.stringify({
|
||||||
|
source: `${renameOldPath.value}${renameOldName.value}`,
|
||||||
|
target: `${renameOldPath.value}${renameNewName.value}`,
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
if (res.status >= 400) {
|
if (res.status >= 400) {
|
||||||
@ -542,6 +551,7 @@ async function renameFile(ren: boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renameOldName.value = ''
|
renameOldName.value = ''
|
||||||
|
renameOldPath.value = ''
|
||||||
renameNewName.value = ''
|
renameNewName.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@
|
|||||||
v-model="newSource.source"
|
v-model="newSource.source"
|
||||||
type="text"
|
type="text"
|
||||||
class="input input-sm input-bordered w-auto"
|
class="input input-sm input-bordered w-auto"
|
||||||
:disabled="newSource.source.includes(configStore.channels[configStore.id].storage_path)"
|
:disabled="newSource.source.includes(configStore.channels[configStore.id].storage)"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
@ -230,9 +230,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
const colorMode = useColorMode()
|
const colorMode = useColorMode()
|
||||||
const { locale, t } = useI18n()
|
const { locale, t } = useI18n()
|
||||||
const { $_, $dayjs } = useNuxtApp()
|
const { $dayjs } = useNuxtApp()
|
||||||
const { width } = useWindowSize({ initialWidth: 800 })
|
const { width } = useWindowSize({ initialWidth: 800 })
|
||||||
const { mediaType } = stringFormatter()
|
const { mediaType } = stringFormatter()
|
||||||
const { processPlaylist, genUID } = playlistOperations()
|
const { processPlaylist, genUID } = playlistOperations()
|
||||||
@ -314,7 +316,7 @@ function closePlayer() {
|
|||||||
|
|
||||||
function setPreviewData(path: string) {
|
function setPreviewData(path: string) {
|
||||||
let fullPath = path
|
let fullPath = path
|
||||||
const storagePath = configStore.channels[configStore.id].storage_path
|
const storagePath = configStore.channels[configStore.id].storage
|
||||||
const lastIndex = storagePath.lastIndexOf('/')
|
const lastIndex = storagePath.lastIndexOf('/')
|
||||||
|
|
||||||
if (!path.includes('/')) {
|
if (!path.includes('/')) {
|
||||||
@ -428,7 +430,7 @@ function loopClips() {
|
|||||||
for (const item of playlistStore.playlist) {
|
for (const item of playlistStore.playlist) {
|
||||||
if (length < configStore.playlistLength) {
|
if (length < configStore.playlistLength) {
|
||||||
item.uid = genUID()
|
item.uid = genUID()
|
||||||
tempList.push($_.cloneDeep(item))
|
tempList.push(cloneDeep(item))
|
||||||
length += item.out - item.in
|
length += item.out - item.in
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@ -493,7 +495,7 @@ async function savePlaylist(save: boolean) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveList = processPlaylist(listDate.value, $_.cloneDeep(playlistStore.playlist), true)
|
const saveList = processPlaylist(listDate.value, cloneDeep(playlistStore.playlist), true)
|
||||||
|
|
||||||
await $fetch(`/api/playlist/${configStore.channels[configStore.id].id}/`, {
|
await $fetch(`/api/playlist/${configStore.channels[configStore.id].id}/`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
import lodash from 'lodash'
|
|
||||||
import type { LoDashStatic } from 'lodash'
|
|
||||||
|
|
||||||
declare module '#app' {
|
|
||||||
interface NuxtApp {
|
|
||||||
$_: LoDashStatic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
declare module '@vue/runtime-core' {
|
|
||||||
interface ComponentCustomProperties {
|
|
||||||
$_: LoDashStatic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineNuxtPlugin((nuxtApp) => {
|
|
||||||
nuxtApp.provide('_', lodash)
|
|
||||||
})
|
|
@ -40,10 +40,10 @@ export const useAuth = defineStore('auth', {
|
|||||||
password,
|
password,
|
||||||
}
|
}
|
||||||
|
|
||||||
await $fetch<LoginObj>('/auth/login/', {
|
await $fetch('/auth/login/', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
async onResponse({ response }) {
|
async onResponse(response: LoginObj) {
|
||||||
code = response.status
|
code = response.status
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -60,7 +60,7 @@ export const useAuth = defineStore('auth', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async obtainUuid() {
|
async obtainUuid() {
|
||||||
await $fetch<DataAuth>('/api/generate-uuid', {
|
await $fetch('/api/generate-uuid', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: this.authHeader,
|
headers: this.authHeader,
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import _ from 'lodash'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
export const useConfig = defineStore('config', {
|
export const useConfig = defineStore('config', {
|
||||||
@ -70,7 +70,7 @@ export const useConfig = defineStore('config', {
|
|||||||
|
|
||||||
this.utcOffset = objs[0].utc_offset
|
this.utcOffset = objs[0].utc_offset
|
||||||
this.channels = objs
|
this.channels = objs
|
||||||
this.channelsRaw = _.cloneDeep(objs)
|
this.channelsRaw = cloneDeep(objs)
|
||||||
this.configCount = objs.length
|
this.configCount = objs.length
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
@ -84,9 +84,9 @@ export const useConfig = defineStore('config', {
|
|||||||
extra_extensions: '',
|
extra_extensions: '',
|
||||||
name: 'Channel 1',
|
name: 'Channel 1',
|
||||||
preview_url: '',
|
preview_url: '',
|
||||||
hls_path: '',
|
public: '',
|
||||||
playlist_path: '',
|
playlists: '',
|
||||||
storage_path: '',
|
storage: '',
|
||||||
uts_offset: 0,
|
uts_offset: 0,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -97,7 +97,7 @@ export const useConfig = defineStore('config', {
|
|||||||
|
|
||||||
async setChannelConfig(obj: Channel): Promise<any> {
|
async setChannelConfig(obj: Channel): Promise<any> {
|
||||||
const authStore = useAuth()
|
const authStore = useAuth()
|
||||||
const stringObj = _.cloneDeep(obj)
|
const stringObj = cloneDeep(obj)
|
||||||
let response
|
let response
|
||||||
|
|
||||||
if (this.channelsRaw.some((e) => e.id === stringObj.id)) {
|
if (this.channelsRaw.some((e) => e.id === stringObj.id)) {
|
||||||
@ -125,7 +125,7 @@ export const useConfig = defineStore('config', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.channels = guiConfigs
|
this.channels = guiConfigs
|
||||||
this.channelsRaw = _.cloneDeep(guiConfigs)
|
this.channelsRaw = cloneDeep(guiConfigs)
|
||||||
this.configCount = guiConfigs.length
|
this.configCount = guiConfigs.length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
import { differenceWith, isEqual, omit } from 'lodash-es'
|
||||||
import utc from 'dayjs/plugin/utc.js'
|
import utc from 'dayjs/plugin/utc.js'
|
||||||
import timezone from 'dayjs/plugin/timezone.js'
|
import timezone from 'dayjs/plugin/timezone.js'
|
||||||
|
|
||||||
@ -28,13 +29,13 @@ export const usePlaylist = defineStore('playlist', {
|
|||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
async getPlaylist(date: string) {
|
async getPlaylist(date: string) {
|
||||||
const { $_, $i18n } = useNuxtApp()
|
const { $i18n } = useNuxtApp()
|
||||||
const authStore = useAuth()
|
const authStore = useAuth()
|
||||||
const configStore = useConfig()
|
const configStore = useConfig()
|
||||||
const indexStore = useIndex()
|
const indexStore = useIndex()
|
||||||
const channel = configStore.channels[configStore.id].id
|
const channel = configStore.channels[configStore.id].id
|
||||||
|
|
||||||
await $fetch<Playlist>(`/api/playlist/${channel}?date=${date}`, {
|
await $fetch(`/api/playlist/${channel}?date=${date}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: authStore.authHeader,
|
headers: authStore.authHeader,
|
||||||
})
|
})
|
||||||
@ -47,8 +48,8 @@ export const usePlaylist = defineStore('playlist', {
|
|||||||
this.playlist.length > 0 &&
|
this.playlist.length > 0 &&
|
||||||
programData.length > 0 &&
|
programData.length > 0 &&
|
||||||
(this.playlist[0].date === date || configStore.playout.playlist.infinit) &&
|
(this.playlist[0].date === date || configStore.playout.playlist.infinit) &&
|
||||||
$_.differenceWith(this.playlist, programData, (a, b) => {
|
differenceWith(this.playlist, programData, (a, b) => {
|
||||||
return $_.isEqual($_.omit(a, ['uid']), $_.omit(b, ['uid']))
|
return isEqual(omit(a, ['uid']), omit(b, ['uid']))
|
||||||
}).length > 0
|
}).length > 0
|
||||||
) {
|
) {
|
||||||
indexStore.msgAlert('warning', $i18n.t('player.unsavedProgram'), 3)
|
indexStore.msgAlert('warning', $i18n.t('player.unsavedProgram'), 3)
|
||||||
|
7
frontend/types/index.d.ts
vendored
7
frontend/types/index.d.ts
vendored
@ -11,6 +11,7 @@ declare global {
|
|||||||
|
|
||||||
interface LoginObj {
|
interface LoginObj {
|
||||||
message: string
|
message: string
|
||||||
|
status: number
|
||||||
user?: {
|
user?: {
|
||||||
id: number
|
id: number
|
||||||
mail: string
|
mail: string
|
||||||
@ -28,9 +29,9 @@ declare global {
|
|||||||
extra_extensions: string | string[]
|
extra_extensions: string | string[]
|
||||||
name: string
|
name: string
|
||||||
preview_url: string
|
preview_url: string
|
||||||
hls_path: string
|
public: string
|
||||||
playlist_path: string
|
playlists: string
|
||||||
storage_path: string
|
storage: string
|
||||||
uts_offset?: number
|
uts_offset?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user