mark and scroll to currenct clip, show when ingest is running

This commit is contained in:
jb-alvarado 2023-04-09 22:28:57 +02:00
parent 9edca39808
commit 3064ac38a4
5 changed files with 92 additions and 57 deletions

View File

@ -31,11 +31,18 @@
</div>
<div class="col time-col counter-col">
<div class="time-str">
{{ secToHMS((playlistStore.remainingSec >= 0) ? playlistStore.remainingSec : 0) }}
{{ secToHMS(playlistStore.remainingSec >= 0 ? playlistStore.remainingSec : 0) }}
</div>
</div>
<div class="col current-clip">
<div class="current-clip-text" :title="filename(playlistStore.currentClip)">
<div
v-if="playlistStore.ingestRuns"
class="current-clip-text"
title="Live Ingest"
>
Live Ingest
</div>
<div v-else class="current-clip-text" :title="filename(playlistStore.currentClip)">
{{ filename(playlistStore.currentClip) }}
</div>
<div class="current-clip-meta">
@ -157,17 +164,17 @@ const videoOptions = ref({
suppressNotSupportedError: true,
autoplay: false,
preload: 'auto',
sources: [] as SourceObject[],
sources: [] as SourceObject[]
})
const httpFlvSource = ref({
type: 'flv',
isLive: true,
url: '',
url: ''
})
const mpegtsOptions = ref({
enableWorker: true,
lazyLoadMaxDuration: 3 * 60,
liveBufferLatencyChasing: true,
liveBufferLatencyChasing: true
})
onMounted(() => {
@ -176,8 +183,8 @@ onMounted(() => {
videoOptions.value.sources = [
{
type: 'application/x-mpegURL',
src: configStore.configGui[configStore.configID].preview_url,
},
src: configStore.configGui[configStore.configID].preview_url
}
]
let player: any
@ -253,7 +260,7 @@ async function playoutStatus() {
await $fetch(`/api/control/${channel}/process/`, {
method: 'POST',
headers: { ...contentType, ...authStore.authHeader },
body: JSON.stringify({ command: 'status' }),
body: JSON.stringify({ command: 'status' })
})
.then((response: any) => {
if (response === 'active') {
@ -277,7 +284,7 @@ async function controlProcess(state: string) {
await $fetch(`/api/control/${channel}/process/`, {
method: 'POST',
headers: { ...contentType, ...authStore.authHeader },
body: JSON.stringify({ command: state }),
body: JSON.stringify({ command: state })
})
setTimeout(() => {
@ -298,7 +305,7 @@ async function controlPlayout(state: string) {
await $fetch(`/api/control/${channel}/playout/`, {
method: 'POST',
headers: { ...contentType, ...authStore.authHeader },
body: JSON.stringify({ control: state }),
body: JSON.stringify({ control: state })
})
setTimeout(() => {

46
package-lock.json generated
View File

@ -10,7 +10,7 @@
"hasInstallScript": true,
"dependencies": {
"@nuxt/types": "^2.16.3",
"@pinia/nuxt": "^0.4.7",
"@pinia/nuxt": "^0.4.8",
"@popperjs/core": "^2.11.7",
"@vueuse/core": "^9.13.0",
"bootstrap": "^5.3.0-alpha3",
@ -20,7 +20,7 @@
"jwt-decode": "^3.1.2",
"lodash": "^4.17.21",
"mpegts.js": "^1.7.3",
"pinia": "^2.0.33",
"pinia": "^2.0.34",
"sortablejs": "^1.15.0",
"sortablejs-vue3": "^1.2.9",
"splitpanes": "^3.1.5",
@ -33,7 +33,7 @@
"@types/lodash": "^4.14.192",
"@types/splitpanes": "^2.2.1",
"@types/video.js": "^7.3.51",
"eslint": "^8.37.0",
"eslint": "^8.38.0",
"eslint-plugin-nuxt": "^4.0.0",
"nuxt": "3.3.3",
"sass": "^1.61.0",
@ -1005,9 +1005,9 @@
}
},
"node_modules/@eslint/js": {
"version": "8.37.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz",
"integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==",
"version": "8.38.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz",
"integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -1628,12 +1628,12 @@
}
},
"node_modules/@pinia/nuxt": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.4.7.tgz",
"integrity": "sha512-ifgA9PO/jmPlK1e/HtkrZa7OMSL8EUOpo8Z1O5vNLRr/OZ42kKGEaY1NbIoCz6dIf/pbkATTNHJmcrlPCo3zSA==",
"version": "0.4.8",
"resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.4.8.tgz",
"integrity": "sha512-E0HKmW+6Ec5HYzomZl86xil2rGPRAqKG1d+slVVLBHC7PFZOM0VIw/1XFO9hwo+EiCuDEXZDReZwTqO7KQsMgQ==",
"dependencies": {
"@nuxt/kit": "^3.0.0",
"pinia": ">=2.0.31"
"pinia": ">=2.0.34"
},
"funding": {
"url": "https://github.com/sponsors/posva"
@ -3603,9 +3603,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001474",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz",
"integrity": "sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==",
"version": "1.0.30001476",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001476.tgz",
"integrity": "sha512-JmpktFppVSvyUN4gsLS0bShY2L9ZUslHLE72vgemBkS43JD2fOvKTKs+GtRwuxrtRGnwJFW0ye7kWRRlLJS9vQ==",
"funding": [
{
"type": "opencollective",
@ -4492,9 +4492,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.355",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.355.tgz",
"integrity": "sha512-056hxzEE4l667YeOccgjhRr5fTiwZ6EIJ4FpzGps4k3YcS8iAhiaBYUBrv5E2LDQJsussscv9EEUwAYKnv+ZKg=="
"version": "1.4.356",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.356.tgz",
"integrity": "sha512-nEftV1dRX3omlxAj42FwqRZT0i4xd2dIg39sog/CnCJeCcL1TRd2Uh0i9Oebgv8Ou0vzTPw++xc+Z20jzS2B6A=="
},
"node_modules/emoji-regex": {
"version": "9.2.2",
@ -4729,15 +4729,15 @@
}
},
"node_modules/eslint": {
"version": "8.37.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz",
"integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==",
"version": "8.38.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz",
"integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.2",
"@eslint/js": "8.37.0",
"@eslint/js": "8.38.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@ -8320,9 +8320,9 @@
}
},
"node_modules/pinia": {
"version": "2.0.33",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.33.tgz",
"integrity": "sha512-HOj1yVV2itw6rNIrR2f7+MirGNxhORjrULL8GWgRwXsGSvEqIQ+SE0MYt6cwtpegzCda3i+rVTZM+AM7CG+kRg==",
"version": "2.0.34",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.0.34.tgz",
"integrity": "sha512-cgOoGUiyqX0SSgX8XelK9+Ri4XA2/YyNtgjogwfzIx1g7iZTaZPxm7/bZYMCLU2qHRiHhxG7SuQO0eBacFNc2Q==",
"dependencies": {
"@vue/devtools-api": "^6.5.0",
"vue-demi": "*"

View File

@ -1,6 +1,6 @@
{
"name": "ffplayout-frontend",
"version": "0.2.5",
"version": "0.3.0",
"description": "Web GUI for ffplayout",
"author": "Jonathan Baecker",
"private": true,
@ -13,7 +13,7 @@
},
"dependencies": {
"@nuxt/types": "^2.16.3",
"@pinia/nuxt": "^0.4.7",
"@pinia/nuxt": "^0.4.8",
"@popperjs/core": "^2.11.7",
"@vueuse/core": "^9.13.0",
"bootstrap": "^5.3.0-alpha3",
@ -23,7 +23,7 @@
"jwt-decode": "^3.1.2",
"lodash": "^4.17.21",
"mpegts.js": "^1.7.3",
"pinia": "^2.0.33",
"pinia": "^2.0.34",
"sortablejs": "^1.15.0",
"sortablejs-vue3": "^1.2.9",
"splitpanes": "^3.1.5",
@ -36,7 +36,7 @@
"@types/lodash": "^4.14.192",
"@types/splitpanes": "^2.2.1",
"@types/video.js": "^7.3.51",
"eslint": "^8.37.0",
"eslint": "^8.38.0",
"eslint-plugin-nuxt": "^4.0.0",
"nuxt": "3.3.3",
"sass": "^1.61.0",

View File

@ -138,6 +138,11 @@
<li
:id="`clip_${index}`"
class="draggable list-group-item playlist-item"
:class="
index === playlistStore.currentClipIndex && listDate === todayDate
? 'active-playlist-clip'
: ''
"
:key="element.uid"
>
<div class="row playlist-row">
@ -478,7 +483,7 @@
'/'
),
true
),
)
]
"
>
@ -545,11 +550,11 @@ const mediaStore = useMedia()
const playlistStore = usePlaylist()
definePageMeta({
middleware: ['auth'],
middleware: ['auth']
})
useHead({
title: 'Player | ffplayout',
title: 'Player | ffplayout'
})
const { configID } = storeToRefs(useConfig())
@ -557,6 +562,7 @@ const { configID } = storeToRefs(useConfig())
const fileImport = ref()
const browserIsLoading = ref(false)
const playlistIsLoading = ref(false)
const todayDate = ref($dayjs().utcOffset(configStore.utcOffset).format('YYYY-MM-DD'))
const listDate = ref($dayjs().utcOffset(configStore.utcOffset).format('YYYY-MM-DD'))
const targetDate = ref($dayjs().utcOffset(configStore.utcOffset).format('YYYY-MM-DD'))
const editId = ref(-1)
@ -566,15 +572,15 @@ const previewUrl = ref('')
const previewOpt = ref()
const isVideo = ref(false)
const selectedFolders = ref([] as string[])
const generateFromAll =ref(false)
const generateFromAll = ref(false)
const browserSortOptions = ref({
group: { name: 'playlist', pull: 'clone', put: false },
sort: false,
sort: false
})
const playlistSortOptions = ref({
group: 'playlist',
animation: 100,
handle: '.grabbing',
handle: '.grabbing'
})
const newSource = ref({
begin: 0,
@ -585,7 +591,7 @@ const newSource = ref({
custom_filter: '',
source: '',
audio: '',
uid: '',
uid: ''
} as PlaylistItem)
onMounted(() => {
@ -601,6 +607,16 @@ watch([listDate, configID], () => {
getPlaylist()
})
function scrollTo(index: number) {
const child = document.getElementById(`clip_${index}`)
if (child) {
const parent = document.getElementById('scroll-container')
const topPos = child.offsetTop
parent.scrollTop = topPos - 50
}
}
async function getPath(path: string) {
browserIsLoading.value = true
await mediaStore.getTree(path)
@ -611,6 +627,12 @@ async function getPlaylist() {
playlistIsLoading.value = true
await playlistStore.getPlaylist(listDate.value)
playlistIsLoading.value = false
if (listDate.value === todayDate.value) {
scrollTo(playlistStore.currentClipIndex)
} else {
scrollTo(0)
}
}
function closePlayer() {
@ -652,7 +674,7 @@ function cloneClip(event: any) {
source: sourcePath,
in: 0,
out: mediaStore.folderTree.files[o].duration,
duration: mediaStore.folderTree.files[o].duration,
duration: mediaStore.folderTree.files[o].duration
})
playlistStore.playlist = processPlaylist(
@ -697,9 +719,9 @@ function setPreviewData(path: string) {
sources: [
{
type: `video/${ext}`,
src: previewUrl.value,
},
],
src: previewUrl.value
}
]
}
} else {
isVideo.value = false
@ -738,7 +760,7 @@ function processSource(evt: any) {
custom_filter: '',
source: '',
audio: '',
uid: '',
uid: ''
}
}
@ -753,7 +775,7 @@ function clearNewSource() {
custom_filter: '',
source: '',
audio: '',
uid: genUID(),
uid: genUID()
}
}
@ -769,7 +791,7 @@ function editPlaylistItem(i: number) {
custom_filter: playlistStore.playlist[i].custom_filter,
source: playlistStore.playlist[i].source,
audio: playlistStore.playlist[i].audio,
uid: playlistStore.playlist[i].uid,
uid: playlistStore.playlist[i].uid
}
}
@ -821,7 +843,7 @@ async function onSubmitImport(evt: any) {
{
method: 'PUT',
headers: authStore.authHeader,
body: formData,
body: formData
}
)
.then(() => {
@ -855,7 +877,7 @@ async function generatePlaylist() {
let payload = {
method: 'POST',
headers: { ...contentType, ...authStore.authHeader },
headers: { ...contentType, ...authStore.authHeader }
} as Payload
if (selectedFolders.value.length > 0 && !generateFromAll.value) {
@ -906,8 +928,8 @@ async function savePlaylist(saveDate: string) {
body: JSON.stringify({
channel: configStore.configGui[configStore.configID].name,
date: saveDate,
program: saveList,
}),
program: saveList
})
})
.then((response: any) => {
indexStore.alertVariant = 'alert-success'
@ -942,7 +964,7 @@ async function savePlaylist(saveDate: string) {
async function deletePlaylist(playlistDate: string) {
await $fetch(`/api/playlist/${configStore.configGui[configStore.configID].id}/${playlistDate}`, {
method: 'DELETE',
headers: { ...contentType, ...authStore.authHeader },
headers: { ...contentType, ...authStore.authHeader }
}).then(() => {
playlistStore.playlist = []
@ -1074,6 +1096,10 @@ function setSelectedFolder(event: any, folder: string) {
.select-all-div {
margin-right: 20px;
}
.active-playlist-clip {
background-color: #405f51 !important;
}
</style>
<style>
@media (max-width: 575px) {

View File

@ -20,11 +20,12 @@ export const usePlaylist = defineStore('playlist', {
playlist: [] as PlaylistItem[],
progressValue: 0,
currentClip: 'No clip is playing',
currentClipIndex: -1,
currentClipIndex: 0,
currentClipStart: 0,
currentClipDuration: 0,
currentClipIn: 0,
currentClipOut: 0,
ingestRuns: false,
remainingSec: 0,
playoutIsRunning: true,
}),
@ -85,6 +86,7 @@ export const usePlaylist = defineStore('playlist', {
this.currentClipDuration = obj.current_media.duration
this.currentClipIn = obj.current_media.seek
this.currentClipOut = obj.current_media.out
this.ingestRuns = obj.ingest_runs
}
})
.catch(() => {