work on player

This commit is contained in:
jb-alvarado 2024-04-08 17:07:03 +02:00
parent 85c2af1266
commit 440944b310
5 changed files with 314 additions and 408 deletions

View File

@ -1,28 +1,30 @@
<template>
<div class="w-full">
<div class="grid grid-cols-1 md:grid-cols-[auto_512px] xl:grid-cols-[512px_auto_450px]">
<div class="order-1 p-1 flex">
<div class="aspect-video w-full">
<video v-if="streamExtension === 'flv'" ref="httpStreamFlv" controls />
<VideoPlayer
class="live-player"
v-else-if="configStore.configGui[configStore.configID]"
:key="configStore.configID"
reference="httpStream"
:options="{
liveui: true,
controls: true,
suppressNotSupportedError: true,
autoplay: false,
preload: 'auto',
sources: [
{
type: 'application/x-mpegURL',
src: configStore.configGui[configStore.configID].preview_url,
},
],
}"
/>
<div class="order-1 p-1">
<div class="bg-base-100 w-full h-full rounded">
<div class="w-full h-full p-2">
<video v-if="streamExtension === 'flv'" ref="httpStreamFlv" controls />
<VideoPlayer
class="live-player"
v-else-if="configStore.configGui[configStore.configID]"
:key="configStore.configID"
reference="httpStream"
:options="{
liveui: true,
controls: true,
suppressNotSupportedError: true,
autoplay: false,
preload: 'auto',
sources: [
{
type: 'application/x-mpegURL',
src: configStore.configGui[configStore.configID].preview_url,
},
],
}"
/>
</div>
</div>
</div>
@ -31,7 +33,7 @@
>
<div class="col-span-1 p-1">
<div
class="w-full h-full bg-base-100 rounded font-['DigitalNumbers-Regular'] p-6 text-3xl 2xl:text-5xl 4xl:text-7xl tracking-tighter flex justify-center items-center"
class="w-full h-full bg-base-100 rounded font-['DigitalNumbers-Regular'] p-6 text-3xl md:text-2xl 2xl:text-5xl 4xl:text-7xl tracking-tighter flex justify-center items-center"
>
{{ timeStr }}
</div>
@ -39,14 +41,14 @@
<div class="col-span-1 p-1 min-h-[50%]">
<div
class="w-full h-full bg-base-100 rounded font-['DigitalNumbers-Regular'] p-6 text-3xl 2xl:text-5xl 4xl:text-7xl tracking-tighter flex justify-center items-center"
class="w-full h-full bg-base-100 rounded font-['DigitalNumbers-Regular'] p-6 text-3xl md:text-2xl 2xl:text-5xl 4xl:text-7xl tracking-tighter flex justify-center items-center"
>
{{ secToHMS(playlistStore.remainingSec >= 0 ? playlistStore.remainingSec : 0) }}
</div>
</div>
<div class="col-span-1 xs:col-span-2 p-1">
<div class="w-full h-full bg-base-100 flex items-center p-3">
<div class="w-full h-full bg-base-100 rounded flex items-center p-3">
<div class="w-full h-full flex flex-col">
<div v-if="playlistStore.ingestRuns" class="h-1/3 font-bold truncate" title="Live Ingest">
Live Ingest
@ -76,7 +78,7 @@
</div>
<div class="order-2 xl:order-3 p-1">
<div class="bg-base-100 h-full flex justify-center">
<div class="bg-base-100 h-full flex justify-center rounded">
<div class="w-full h-full grid grid-cols-3">
<div class="text-center">
<div class="w-full h-1/2 aspect-square p-2">

View File

@ -5,13 +5,14 @@
<li
v-for="(crumb, index) in mediaStore.crumbs"
:key="index"
:active="index === mediaStore.crumbs.length - 1"
@click="getPath(crumb.path)"
v-on:drop="handleDrop($event, crumb.path, null)"
v-on:dragover="handleDragOver"
v-on:dragleave="handleDragLeave"
>
<button v-if="mediaStore.crumbs.length > 1 && mediaStore.crumbs.length - 1 > index">
<button
v-if="mediaStore.crumbs.length > 1 && mediaStore.crumbs.length - 1 > index"
@click="mediaStore.getTree(crumb.path)"
>
<i class="bi-folder-fill me-1" />
{{ crumb.text }}
</button>
@ -20,9 +21,9 @@
</ul>
</nav>
<div class=" h-[calc(100%-34px)] bg-base-100">
<div class="h-[calc(100%-34px)] bg-base-100">
<div
v-if="browserIsLoading"
v-if="mediaStore.isLoading"
class="w-[calc(100%-16px)] h-[calc(100%-174px)] absolute z-10 flex justify-center bg-base-100/70"
>
<span class="loading loading-spinner loading-lg"></span>
@ -42,7 +43,7 @@
>
<button
class="truncate text-left"
@click="getPath(`/${parent(mediaStore.folderTree.source)}/${folder.name}`)"
@click="mediaStore.getTree(`/${parent(mediaStore.folderTree.source)}/${folder.name}`)"
>
<i class="bi-folder-fill" />
{{ folder.name }}
@ -80,7 +81,7 @@
>
<button
class="truncate text-left"
@click="getPath(`/${mediaStore.folderTree.source}/${folder.name}`)"
@click="mediaStore.getTree(`/${mediaStore.folderTree.source}/${folder.name}`)"
>
<i class="bi-folder-fill" />
{{ folder.name }}
@ -138,8 +139,6 @@
<button
class="w-7 opacity-30 hover:opacity-100"
data-bs-toggle="modal"
data-bs-target="#deleteModal"
@click="
;(showDeleteModal = true),
(deleteName = `/${mediaStore.folderTree.source}/${element.name}`.replace(
@ -284,8 +283,6 @@ const currentProgress = ref(0)
const lastPath = ref('')
const xhr = ref(new XMLHttpRequest())
const fileRefs = ref([] as any[])
onMounted(async () => {
let config_extensions = configStore.configPlayout.storage.extensions
let extra_extensions = configStore.configGui[configStore.configID].extra_extensions
@ -305,12 +302,12 @@ onMounted(async () => {
extensions.value = exts.join(', ')
if (!mediaStore.folderTree.parent) {
await getPath('')
await mediaStore.getTree('')
}
})
watch([configID], () => {
getPath('')
mediaStore.getTree('')
})
function handleDragStart(event: any, itemData: any) {
@ -339,24 +336,18 @@ function handleDragLeave(event: any) {
async function handleDrop(event: any, targetFolder: any, isParent: boolean | null) {
const itemData = JSON.parse(event.dataTransfer.getData('application/json'))
const source = `/${mediaStore.folderTree.source}/${itemData.name}`.replace(
/\/[/]+/g,
'/'
)
const source = `/${mediaStore.folderTree.source}/${itemData.name}`.replace(/\/[/]+/g, '/')
let target
if (isParent === null) {
target = `${targetFolder}/${itemData.name}`.replace(/\/[/]+/g, '/')
} else if (isParent) {
target = `/${parent(mediaStore.folderTree.source)}/${targetFolder.name}/${
itemData.name
}`.replace(/\/[/]+/g, '/')
target = `/${parent(mediaStore.folderTree.source)}/${targetFolder.name}/${itemData.name}`.replace(
/\/[/]+/g,
'/'
)
} else {
target =
`/${mediaStore.folderTree.source}/${targetFolder.name}/${itemData.name}`.replace(
/\/[/]+/g,
'/'
)
target = `/${mediaStore.folderTree.source}/${targetFolder.name}/${itemData.name}`.replace(/\/[/]+/g, '/')
}
event.target.style.fontWeight = null
@ -373,7 +364,7 @@ async function handleDrop(event: any, targetFolder: any, isParent: boolean | nul
body: JSON.stringify({ source, target }),
})
.then(() => {
getPath(mediaStore.folderTree.source)
mediaStore.getTree(mediaStore.folderTree.source)
})
.catch((e) => {
indexStore.msgAlert('alert-error', `Delete error: ${e}`, 3)
@ -381,12 +372,6 @@ async function handleDrop(event: any, targetFolder: any, isParent: boolean | nul
}
}
async function getPath(path: string) {
browserIsLoading.value = true
await mediaStore.getTree(path)
browserIsLoading.value = false
}
function setPreviewData(path: string) {
/*
Set path and player options for video preview.
@ -446,7 +431,7 @@ async function deleteFileOrFolder(del: boolean) {
if (response.status !== 200) {
indexStore.msgAlert('alert-error', `${await response.text()}`, 5)
}
getPath(mediaStore.folderTree.source)
mediaStore.getTree(mediaStore.folderTree.source)
})
.catch((e) => {
indexStore.msgAlert('alert-error', `Delete error: ${e}`, 5)
@ -474,7 +459,7 @@ async function renameFile(ren: boolean) {
body: JSON.stringify({ source: renameOldName.value, target: renameNewName.value }),
})
.then(() => {
getPath(mediaStore.folderTree.source)
mediaStore.getTree(mediaStore.folderTree.source)
})
.catch((e) => {
indexStore.msgAlert('alert-error', `Delete error: ${e}`, 3)
@ -516,7 +501,7 @@ async function createFolder(create: boolean) {
indexStore.alertVariant = 'alert-error'
})
getPath(lastPath.value)
mediaStore.getTree(lastPath.value)
}
folderName.value = {} as Folder
@ -588,7 +573,7 @@ async function uploadFiles(upl: boolean) {
}
uploadTask.value = 'Done...'
getPath(lastPath.value)
mediaStore.getTree(lastPath.value)
setTimeout(() => {
fileInputName.value = null

View File

@ -1,165 +1,139 @@
<template>
<div>
<div class="h-full">
<Control />
<div class="date-row">
<div class="col">
<input type="date" class="form-control date-div mt-2 mb-2" v-model="listDate" />
<div class="flex justify-end p-1">
<div>
<input type="date" class="input input-sm input-bordered w-full max-w-xs" v-model="listDate" />
</div>
</div>
<!-- <splitpanes class="container list-row pane-row player-container">
<pane class="mobile-hidden" min-size="14" max-size="80" size="20">
<div v-if="browserIsLoading" class="d-flex justify-content-center loading-overlay">
<div class="spinner-border" role="status" />
</div>
<div v-if="mediaStore.folderTree.parent && mediaStore.crumbs">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li
class="breadcrumb-item"
v-for="(crumb, index) in mediaStore.crumbs"
:key="index"
:active="index === mediaStore.crumbs.length - 1"
@click="getPath(crumb.path)"
>
<a v-if="mediaStore.crumbs.length > 1 && mediaStore.crumbs.length - 1 > index" href="#">
{{ crumb.text }}
</a>
<span v-else>{{ crumb.text }}</span>
</li>
</ol>
</nav>
</div>
<ul class="list-group media-browser-scroll browser-div">
<li
class="list-group-item browser-item"
v-for="folder in mediaStore.folderTree.folders"
:key="folder.uid"
<div class="p-1 min-h-[500px] h-[calc(100vh-800px)] xl:h-[calc(100vh-480px)]">
<splitpanes class="border border-my-gray rounded">
<pane class="h-full" min-size="0" max-size="80" size="20">
<div
v-if="mediaStore.isLoading"
class="w-full h-full absolute z-10 flex justify-center bg-base-100/70"
>
<div class="row">
<div class="col-1 browser-icons-col">
<i class="bi-folder-fill browser-icons" />
</div>
<div class="col browser-item-text">
<a
class="link-light"
href="#"
@click="getPath(`/${mediaStore.folderTree.source}/${folder.name}`)"
>
{{ folder.name }}
</a>
</div>
</div>
</li>
<Sortable :list="mediaStore.folderTree.files" :options="browserSortOptions" item-key="name">
<template #item="{ element, index }">
<li
:id="`file_${index}`"
class="draggable list-group-item browser-item"
:key="element.name"
>
<div class="row">
<div class="col-1 browser-icons-col">
<i
v-if="mediaType(element.name) === 'audio'"
class="bi-music-note-beamed browser-icons"
/>
<i
v-else-if="mediaType(element.name) === 'video'"
class="bi-film browser-icons"
/>
<i
v-else-if="mediaType(element.name) === 'image'"
class="bi-file-earmark-image browser-icons"
/>
<i v-else class="bi-file-binary browser-icons" />
</div>
<div class="col browser-item-text grabbing">
{{ element.name }}
</div>
<div class="col-1 browser-play-col">
<a
href="#"
class="btn-link"
data-bs-toggle="modal"
data-bs-target="#previewModal"
@click="setPreviewData(element.name)"
>
<i class="bi-play-fill" />
</a>
</div>
<div class="col-1 browser-dur-col">
<span class="duration">{{ toMin(element.duration) }}</span>
</div>
</div>
</li>
</template>
</Sortable>
</ul>
</pane>
<pane class="playlist-pane">
<div class="playlist-container">
<ul class="list-group list-group-header">
<li class="list-group-item">
<div class="row playlist-row">
<div class="col-1 timecode">Start</div>
<div class="col">File</div>
<div class="col-1 text-center playlist-input">Play</div>
<div class="col-1 timecode">Duration</div>
<div class="col-1 timecode mobile-hidden">In</div>
<div class="col-1 timecode mobile-hidden">Out</div>
<div class="col-1 text-center playlist-input mobile-hidden">Ad</div>
<div class="col-1 text-center playlist-input">Edit</div>
<div class="col-1 text-center playlist-input mobile-hidden">Delete</div>
</div>
</li>
</ul>
<div v-if="playlistIsLoading" class="d-flex justify-content-center loading-overlay">
<div class="spinner-border" role="status" />
<span class="loading loading-spinner loading-lg" />
</div>
<div id="scroll-container">
<Sortable
:list="playlistStore.playlist"
item-key="uid"
class="list-group playlist-list-group"
:style="`height: ${
playlistStore.playlist ? playlistStore.playlist.length * 38 + 76 : 300
}px`"
tag="ul"
:options="playlistSortOptions"
@add="cloneClip"
@end="moveItemInArray"
>
<div class="bg-base-100 border-b border-my-gray">
<div v-if="mediaStore.folderTree.parent && mediaStore.crumbs">
<nav class="breadcrumbs px-3">
<ul>
<li v-for="(crumb, index) in mediaStore.crumbs" :key="index">
<button
v-if="mediaStore.crumbs.length > 1 && mediaStore.crumbs.length - 1 > index"
@click="mediaStore.getTree(crumb.path)"
>
<i class="bi-folder-fill me-1" />
{{ crumb.text }}
</button>
<span v-else><i class="bi-folder-fill me-1" />{{ crumb.text }}</span>
</li>
</ul>
</nav>
</div>
</div>
<ul class="h-[calc(100%-40px)] overflow-auto m-1">
<li class="flex px-1" v-for="folder in mediaStore.folderTree.folders" :key="folder.uid">
<button
class="truncate"
@click="mediaStore.getTree(`/${mediaStore.folderTree.source}/${folder.name}`)"
>
<i class="bi-folder-fill" />
{{ folder.name }}
</button>
</li>
<Sortable :list="mediaStore.folderTree.files" :options="browserSortOptions" item-key="name">
<template #item="{ element, index }">
<li
:id="`clip_${index}`"
class="draggable list-group-item playlist-item"
:class="
index === playlistStore.currentClipIndex && listDate === todayDate
? 'active-playlist-clip'
: ''
"
:key="element.uid"
:id="`file_${index}`"
class="draggable px-1 grid grid-cols-[auto_110px]"
:key="element.name"
>
<div class="row playlist-row">
<div class="col-1 timecode">{{ secondsToTime(element.begin) }}</div>
<div class="col grabbing filename">{{ filename(element.source) }}</div>
<div class="col-1 text-center playlist-input">
<a
href="#"
class="btn-link"
data-bs-toggle="modal"
data-bs-target="#previewModal"
@click="setPreviewData(element.source)"
>
<div class="truncate cursor-grab">
<i v-if="mediaType(element.name) === 'audio'" class="bi-music-note-beamed" />
<i v-else-if="mediaType(element.name) === 'video'" class="bi-film" />
<i
v-else-if="mediaType(element.name) === 'image'"
class="bi-file-earmark-image"
/>
<i v-else class="bi-file-binary" />
{{ element.name }}
</div>
<div>
<button
class="w-7"
@click=";(showPreviewModal = true), setPreviewData(element.name)"
>
<i class="bi-play-fill" />
</button>
<div class="inline-block w-[82px]">{{ toMin(element.duration) }}</div>
</div>
</li>
</template>
</Sortable>
</ul>
</pane>
<pane>
<div class="w-full h-full">
<div
class="grid grid-cols-[70px_auto_50px_70px_70px_70px_30px_60px_80px] bg-base-100 py-2 px-3 border-b border-my-gray"
>
<div>Start</div>
<div>File</div>
<div class="text-center">Play</div>
<div class="">Duration</div>
<div class="hidden md:flex">In</div>
<div class="hidden md:flex">Out</div>
<div class="hidden md:flex justify-center">Ad</div>
<div class="text-center">Edit</div>
<div class="hidden md:flex justify-center">Delete</div>
</div>
<div
v-if="playlistIsLoading"
class="w-full h-full absolute z-10 flex justify-center bg-base-100/70"
>
<span class="loading loading-spinner loading-lg" />
</div>
<div class="h-full overflow-auto">
<Sortable
:list="playlistStore.playlist"
item-key="uid"
class=""
:style="`height: ${
playlistStore.playlist ? playlistStore.playlist.length * 38 + 76 : 300
}px`"
tag="ul"
:options="playlistSortOptions"
@add="cloneClip"
@end="moveItemInArray"
>
<template #item="{ element, index }">
<li
:id="`clip_${index}`"
class="draggable bg-base-300 even:bg-base-100 grid grid-cols-[70px_auto_50px_70px_70px_70px_30px_60px_80px] h-[38px] px-3 py-[8px]"
:class="
index === playlistStore.currentClipIndex && listDate === todayDate
? 'active-playlist-clip'
: ''
"
:key="element.uid"
>
<div>{{ secondsToTime(element.begin) }}</div>
<div class="grabbing truncate cursor-grab">{{ filename(element.source) }}</div>
<div class="text-center">
<button @click=";(showPreviewModal = true), setPreviewData(element.source)">
<i class="bi-play-fill" />
</a>
</button>
</div>
<div class="col-1 timecode">{{ secToHMS(element.duration) }}</div>
<div class="col-1 timecode mobile-hidden">{{ secToHMS(element.in) }}</div>
<div class="col-1 timecode mobile-hidden">{{ secToHMS(element.out) }}</div>
<div class="col-1 text-center playlist-input mobile-hidden">
<div>{{ secToHMS(element.duration) }}</div>
<div class="hidden md:flex">{{ secToHMS(element.in) }}</div>
<div class="hidden md:flex">{{ secToHMS(element.out) }}</div>
<div class="hidden md:flex justify-center pt-[3px]">
<input
class="form-check-input"
class="checkbox checkbox-xs rounded"
type="checkbox"
:checked="
element.category && element.category === 'advertisement'
@ -169,180 +143,145 @@
@change="setCategory($event, element)"
/>
</div>
<div class="col-1 text-center playlist-input">
<a
href="#"
class="btn-link"
data-bs-toggle="modal"
data-bs-target="#sourceModal"
@click="editPlaylistItem(index)"
>
<div class="text-center">
<button @click=";(showSourceModal = true), editPlaylistItem(index)">
<i class="bi-pencil-square" />
</a>
</button>
</div>
<div class="col-1 text-center playlist-input mobile-hidden">
<a href="#" class="btn-link" @click="deletePlaylistItem(index)">
<div class="text-center hidden md:flex justify-center">
<button @click="deletePlaylistItem(index)">
<i class="bi-x-circle-fill" />
</a>
</button>
</div>
</div>
</li>
</template>
</Sortable>
</li>
</template>
</Sortable>
</div>
</div>
</div>
</pane>
</splitpanes>
</pane>
</splitpanes>
</div>
<div class="btn-group media-button mb-3">
<div class="btn btn-primary" title="Copy Playlist" data-bs-toggle="modal" data-bs-target="#copyModal">
<div class="join flex justify-end m-3">
<button
class="btn btn-sm btn-primary join-item"
title="Copy Playlist"
data-bs-toggle="modal"
data-bs-target="#copyModal"
>
<i class="bi-files" />
</div>
<div
</button>
<button
v-if="!configStore.configPlayout.playlist.loop"
class="btn btn-primary"
class="btn btn-sm btn-primary join-item"
title="Loop Clips in Playlist"
@click="loopClips()"
>
<i class="bi-view-stacked" />
</div>
<div
class="btn btn-primary"
</button>
<button
class="btn btn-sm btn-primary join-item"
title="Add (remote) Source to Playlist"
data-bs-toggle="modal"
data-bs-target="#sourceModal"
@click="clearNewSource()"
@click="showSourceModal = true"
>
<i class="bi-file-earmark-plus" />
</div>
<div
class="btn btn-primary"
</button>
<button
class="btn btn-sm btn-primary join-item"
title="Import text/m3u file"
data-bs-toggle="modal"
data-bs-target="#importModal"
>
<i class="bi-file-text" />
</div>
<div
class="btn btn-primary"
</button>
<button
class="btn btn-sm btn-primary join-item"
title="Generate a randomized Playlist"
data-bs-toggle="modal"
data-bs-target="#generateModal"
@click="mediaStore.getTree('', true)"
>
<i class="bi-sort-down-alt" />
</div>
<div class="btn btn-primary" title="Reset Playlist" @click="getPlaylist()">
</button>
<button class="btn btn-sm btn-primary join-item" title="Reset Playlist" @click="getPlaylist()">
<i class="bi-arrow-counterclockwise" />
</div>
<div class="btn btn-primary" title="Save Playlist" @click="savePlaylist(listDate)">
</button>
<button class="btn btn-sm btn-primary join-item" title="Save Playlist" @click="savePlaylist(listDate)">
<i class="bi-download" />
</div>
<div class="btn btn-primary" title="Delete Playlist" data-bs-toggle="modal" data-bs-target="#deleteModal">
</button>
<button
class="btn btn-sm btn-primary join-item"
title="Delete Playlist"
data-bs-toggle="modal"
data-bs-target="#deleteModal"
>
<i class="bi-trash" />
</div>
</div>-->
<div id="previewModal" class="modal" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-xl">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="previewModalLabel">Preview: {{ previewName }}</h1>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Cancel"
@click="closePlayer()"
></button>
</div>
<div class="modal-body">
<VideoPlayer v-if="isVideo && previewOpt" reference="previewPlayer" :options="previewOpt" />
<img v-else :src="previewUrl" class="img-fluid" :alt="previewName" />
</div>
</div>
</div>
</button>
</div>
<div id="sourceModal" class="modal" tabindex="-1" aria-labelledby="sourceModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="sourceModalLabel">Add/Edit Source</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cancel"></button>
<Modal :show="showPreviewModal" :title="`Preview: ${previewName}`" :modal-action="closePlayer">
<div class="w-[1024px] max-w-full aspect-video">
<VideoPlayer v-if="isVideo && previewOpt" reference="previewPlayer" :options="previewOpt" />
<img v-else :src="previewUrl" class="img-fluid" :alt="previewName" />
</div>
</Modal>
<Modal :show="showSourceModal" title="Add/Edit Source" :modal-action="processSource">
<div>
<label class="form-control w-full mt-3">
<div class="label">
<span class="label-text">In</span>
</div>
<form @reset="clearNewSource">
<div class="modal-body">
<label for="in-input" class="form-label">In</label>
<input
type="number"
class="form-control"
id="in-input"
aria-describedby="in"
v-model.number="newSource.in"
/>
<label for="out-input" class="form-label mt-2">Out</label>
<input
type="number"
class="form-control"
id="out-input"
aria-describedby="out"
v-model.number="newSource.out"
/>
<label for="duration-input" class="form-label mt-2">Duration</label>
<input
type="number"
class="form-control"
id="duration-input"
aria-describedby="out"
v-model.number="newSource.duration"
/>
<label for="source-input" class="form-label mt-2">Source</label>
<input
type="text"
class="form-control"
id="source-input"
aria-describedby="out"
v-model="newSource.source"
/>
<label for="audio-input" class="form-label mt-2">Audio</label>
<input
type="text"
class="form-control"
id="audio-input"
aria-describedby="out"
v-model="newSource.audio"
/>
<label for="filter-input" class="form-label mt-2">Custom Filter</label>
<input
type="text"
class="form-control"
id="filter-input"
aria-describedby="out"
v-model="newSource.custom_filter"
/>
<div class="form-check">
<label class="form-check-label" for="ad-input"> Advertisement </label>
<input class="form-check-input" type="checkbox" value="" id="ad-input" @click="isAd" />
</div>
</div>
<div class="modal-footer">
<button type="reset" class="btn btn-primary" data-bs-dismiss="modal" aria-label="Cancel">
Cancel
</button>
<button
type="submit"
class="btn btn-primary"
data-bs-dismiss="modal"
@click="processSource"
>
Ok
</button>
</div>
</form>
<input type="number" class="input input-sm input-bordered w-full" v-model.number="newSource.in" />
</label>
<label class="form-control w-full mt-3">
<div class="label">
<span class="label-text">Out</span>
</div>
<input type="number" class="input input-sm input-bordered w-full" v-model.number="newSource.out" />
</label>
<label class="form-control w-full mt-3">
<div class="label">
<span class="label-text">Duration</span>
</div>
<input
type="number"
class="input input-sm input-bordered w-full"
v-model.number="newSource.duration"
/>
</label>
<label class="form-control w-full mt-3">
<div class="label">
<span class="label-text">Source</span>
</div>
<input type="text" class="input input-sm input-bordered w-full" v-model="newSource.source" />
</label>
<label class="form-control w-full mt-3">
<div class="label">
<span class="label-text">Audio</span>
</div>
<input type="text" class="input input-sm input-bordered w-full" v-model="newSource.audio" />
</label>
<label class="form-control w-full mt-3">
<div class="label">
<span class="label-text">Custom Filter</span>
</div>
<input type="text" class="input input-sm input-bordered w-full" v-model="newSource.custom_filter" />
</label>
<div class="form-control">
<label class="cursor-pointer label">
<span class="label-text">Advertisement</span>
<input type="checkbox" class="checkbox checkbox-sm" @click="isAd" />
</label>
</div>
</div>
</div>
</Modal>
<div id="importModal" class="modal" tabindex="-1" aria-labelledby="importModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
@ -454,10 +393,7 @@
role="tab"
aria-controls="v-pills-playout"
aria-selected="false"
@click="
advancedGenerator = true,
resetCheckboxes()
"
@click=";(advancedGenerator = true), resetCheckboxes()"
>
Advanced
</button>
@ -723,10 +659,7 @@
type="button"
class="btn btn-primary"
data-bs-dismiss="modal"
@click="
resetCheckboxes(),
resetTemplate()
"
@click="resetCheckboxes(), resetTemplate()"
>
Cancel
</button>
@ -747,8 +680,6 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { Splitpanes, Pane } from 'splitpanes'
import 'splitpanes/dist/splitpanes.css'
const { $_, $dayjs } = useNuxtApp()
const { secToHMS, filename, secondsToTime, toMin, mediaType } = stringFormatter()
@ -769,13 +700,16 @@ const { configID } = storeToRefs(useConfig())
const advancedGenerator = ref(false)
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)
const textFile = ref()
const showPreviewModal = ref(false)
const showSourceModal = ref(false)
const previewName = ref('')
const previewUrl = ref('')
const previewOpt = ref()
@ -818,14 +752,14 @@ const template = ref({
onMounted(() => {
if (!mediaStore.folderTree.parent) {
getPath('')
mediaStore.getTree('')
}
getPlaylist()
})
watch([listDate, configID], () => {
getPath('')
mediaStore.getTree('')
getPlaylist()
})
@ -839,12 +773,6 @@ function scrollTo(index: number) {
}
}
async function getPath(path: string) {
browserIsLoading.value = true
await mediaStore.getTree(path)
browserIsLoading.value = false
}
async function getPlaylist() {
playlistIsLoading.value = true
await playlistStore.getPlaylist(listDate.value)
@ -858,6 +786,7 @@ async function getPlaylist() {
}
function closePlayer() {
showPreviewModal.value = false
isVideo.value = false
}
@ -992,43 +921,29 @@ function setPreviewData(path: string) {
}
}
function processSource(evt: any) {
evt.preventDefault()
function processSource(process: boolean) {
showSourceModal.value = false
if (editId.value === -1) {
playlistStore.playlist.push(newSource.value)
playlistStore.playlist = processPlaylist(
configStore.startInSec,
configStore.playlistLength,
playlistStore.playlist,
false
)
} else {
playlistStore.playlist[editId.value] = newSource.value
playlistStore.playlist = processPlaylist(
configStore.startInSec,
configStore.playlistLength,
playlistStore.playlist,
false
)
editId.value = -1
if (process) {
if (editId.value === -1) {
playlistStore.playlist.push(newSource.value)
playlistStore.playlist = processPlaylist(
configStore.startInSec,
configStore.playlistLength,
playlistStore.playlist,
false
)
} else {
playlistStore.playlist[editId.value] = newSource.value
playlistStore.playlist = processPlaylist(
configStore.startInSec,
configStore.playlistLength,
playlistStore.playlist,
false
)
}
}
newSource.value = {
begin: 0,
in: 0,
out: 0,
duration: 0,
category: '',
custom_filter: '',
source: '',
audio: '',
uid: '',
}
}
function clearNewSource() {
editId.value = -1
newSource.value = {
begin: 0,

View File

@ -9,11 +9,13 @@ export const useMedia = defineStore('media', {
folderTree: {} as FileFolderObject,
folderList: {} as FolderObject,
folderCrumbs: [] as Crumb[],
isLoading: false,
}),
getters: {},
actions: {
async getTree(path: string, foldersOnly: boolean = false) {
this.isLoading = true
const authStore = useAuth()
const configStore = useConfig()
const indexStore = useIndex()
@ -72,6 +74,8 @@ export const useMedia = defineStore('media', {
this.folderTree = data
}
})
}
this.isLoading = false
},
},
})

View File

@ -65,7 +65,7 @@ module.exports = {
'--base-100-odd': '#ececec',
'--my-accent': '#f28c1b',
'--link-hover': '#f4ae61',
'--my-gray': '#707070',
'--my-gray': '#888888',
'--my-gray-text': '#6a6a6a',
'--my-text': '#141414',
'--my-shadow': '#e6e6e6',
@ -93,7 +93,7 @@ module.exports = {
'--base-100-odd': '#3d3d3d',
'--my-accent': '#f28c1b',
'--link-hover': '#f4ae61',
'--my-gray': '#aaaaaa',
'--my-gray': '#919191',
'--my-gray-text': '#bababa',
'--my-text': '#eeeeee',
'--my-shadow': '#111',