mark and scroll to currenct clip, show when ingest is running
This commit is contained in:
parent
9edca39808
commit
3064ac38a4
@ -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
46
package-lock.json
generated
@ -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": "*"
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
@ -569,12 +575,12 @@ const selectedFolders = ref([] as string[])
|
||||
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) {
|
||||
|
@ -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(() => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user