Skip to content

Commit

Permalink
✔ Fixed freeze when adding new action and media tab was open
Browse files Browse the repository at this point in the history
- Fixed slide background showing when clear action was set
- Fixed update popup in prerelease
- Better shows loading
- Fixed shows not loading when loading many
- Fixed thumbnails not generating after failed attempts
  • Loading branch information
vassbo committed Jun 27, 2024
1 parent 1027481 commit 51597f8
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 158 deletions.
4 changes: 4 additions & 0 deletions src/frontend/components/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ export function addSlideAction(slideIndex: number, actionId: string, actionValue
history({ id: "SHOW_LAYOUT", newData: { key: "actions", data: actions, indexes: [slideIndex] } })
}

export function slideHasAction(actions: any, key: string) {
return actions?.slideActions?.find((a) => a.triggers?.includes(key))
}

// extra names

const namedObjects = {
Expand Down
23 changes: 13 additions & 10 deletions src/frontend/components/drawer/media/MediaLoader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
export let loaded: boolean = false
export let resolution: Resolution | null = null
export let duration: number = 0
export let getDuration: boolean = false
export let videoElem: any = null
$: if (path) loaded = false
Expand All @@ -39,7 +40,7 @@
$: if (mediaStyle.speed && videoElem) videoElem.playbackRate = mediaStyle.speed
$: if (!videoElem) duration = 0
function getDuration() {
function getCurrentDuration() {
if (!videoElem || duration) return
duration = videoElem.duration
Expand Down Expand Up @@ -71,15 +72,17 @@
$: useOriginal = hover || loadFullImage || retryCount > 5 || !thumbnailPath
// get duration
$: if (type === "video" && thumbnailPath) getVideoDuration()
$: if (getDuration && type === "video" && thumbnailPath) getVideoDuration()
function getVideoDuration() {
let video = document.createElement("video")
video.onloadeddata = () => {
duration = video.duration || 0
// video.pause()
video.src = ""
}
video.src = path
setTimeout(() => {
let video = document.createElement("video")
video.onloadeddata = () => {
duration = video.duration || 0
// video.pause()
video.src = ""
}
video.src = path
}, 20)
}
</script>

Expand Down Expand Up @@ -109,7 +112,7 @@
{/key}
{/if}
{#if type === "video" && useOriginal}
<video style="pointer-events: none;position: absolute;width: 100%;height: 100%;object-fit: {mediaStyle.fit};" bind:this={videoElem} on:error={reload} src={path} on:canplaythrough={getDuration}>
<video style="pointer-events: none;position: absolute;width: 100%;height: 100%;object-fit: {mediaStyle.fit};" bind:this={videoElem} on:error={reload} src={path} on:canplaythrough={getCurrentDuration}>
<track kind="captions" />
</video>
{/if}
Expand Down
49 changes: 28 additions & 21 deletions src/frontend/components/drawer/timers/timers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,36 +45,43 @@ export function getTimer(ref: any) {
export function createGlobalTimerFromLocalTimer(showId: string | undefined) {
if (!showId) return

showsCache.update((a) => {
if (!a[showId]?.slides) return a
let currentShow = _show(showId).get()
if (!currentShow?.slides) return

let timerCreated: boolean = false

Object.keys(a[showId].slides).forEach(checkSlide)
function checkSlide(slideId) {
let items: any[] = a[showId!].slides[slideId].items
Object.keys(currentShow.slides).forEach(checkSlide)
function checkSlide(slideId) {
let items: any[] = currentShow.slides[slideId].items

// TODO: "backup" global timer to show item.timer
// TODO: "backup" global timer to show item.timer

let timerIndex = items.findIndex((a) => !a.timerId && a.timer)
while (timerIndex >= 0) {
let globalTimerId = uid()
a[showId!].slides[slideId].items[timerIndex].timerId = globalTimerId
let timerIndex = items.findIndex((a) => !a.timerId && a.timer)
while (timerIndex >= 0) {
timerCreated = true
let globalTimerId = uid()
currentShow.slides[slideId].items[timerIndex].timerId = globalTimerId

timers.update((t) => {
let globalTimer = clone(a[showId!].slides[slideId].items[timerIndex].timer)
globalTimer.name = a[showId!].name
delete globalTimer.id
timers.update((t) => {
let globalTimer = clone(currentShow.slides[slideId].items[timerIndex].timer)
globalTimer.name = currentShow.name
delete globalTimer.id

// pre 0.5.3
if (globalTimer.type === "countdown") globalTimer.type = "counter"
// pre 0.5.3
if (globalTimer.type === "countdown") globalTimer.type = "counter"

t[globalTimerId] = globalTimer
return t
})
t[globalTimerId] = globalTimer
return t
})

timerIndex = items.findIndex((a) => !a.timerId && a.timer)
}
timerIndex = items.findIndex((a) => !a.timerId && a.timer)
}
}

if (!timerCreated) return

showsCache.update((a) => {
a[showId] = currentShow
return a
})
}
Expand Down
3 changes: 2 additions & 1 deletion src/frontend/components/edit/editors/SlideEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import DropArea from "../../system/DropArea.svelte"
import Snaplines from "../../system/Snaplines.svelte"
import Editbox from "../editbox/Editbox.svelte"
import { slideHasAction } from "../../actions/actions"
$: currentShow = $activeShow?.id
$: if (currentShow && $showsCache[currentShow] && $activeEdit.slide === null && _show("active").slides().get().length) activeEdit.set({ slide: 0, items: [] })
Expand Down Expand Up @@ -44,7 +45,7 @@
$: if (!bgId) {
ref?.forEach((a, i) => {
if (i <= $activeEdit.slide! && !a.data.disabled) {
if (a.data.actions?.clearBackground) bgId = null
if (slideHasAction(a.data?.actions, "clear_background")) bgId = null
else if (a.data.background) bgId = a.data.background
if (a.data.background && currentShow && $showsCache[currentShow].media[a.data.background]?.loop === false) bgId = null
}
Expand Down
48 changes: 17 additions & 31 deletions src/frontend/components/helpers/T.svelte
Original file line number Diff line number Diff line change
@@ -1,37 +1,23 @@
<script lang="ts">
import { dictionary, language } from "../../stores"
import { dictionary, language } from "../../stores"
export let id: string
export let index: number = 0
export let lowercase: boolean = false
// let pre = '', suf = '';
let category: string, key: string
// if (id.includes('$:')) {
// pre = id.slice(0, id.indexOf('$:'));
// suf = id.slice(id.indexOf(':$') + 2, id.length);
// id = id.slice(id.indexOf('$:') + 2, id.indexOf(':$'));
// let category = id.slice(0, id.indexOf('.'));
// let key = id.slice(id.indexOf('.') + 1, id.length);
// }
if (id.includes(".")) {
category = id.slice(0, id.indexOf(".")).replace("$:", "")
key = id.slice(id.indexOf(".") + 1, id.length).replace(":$", "")
}
export let id: string
export let index: number = 0
export let lowercase: boolean = false
let category: string, key: string
if (id?.includes(".")) {
category = id.slice(0, id.indexOf(".")).replace("$:", "")
key = id.slice(id.indexOf(".") + 1, id.length).replace(":$", "")
}
</script>

{#key language}
{#if $dictionary[category]?.[key]?.includes("{}")}
{$dictionary[category]?.[key].split("{}")[index] || `[${id}]`}
{:else if lowercase}
{$dictionary[category]?.[key].toLowerCase() || `[${id}]`}
{:else}
{$dictionary[category]?.[key] || `[${id}]`}
{/if}
{#if $dictionary[category]?.[key]?.includes("{}")}
{$dictionary[category]?.[key].split("{}")[index] || `[${id}]`}
{:else if lowercase}
{$dictionary[category]?.[key].toLowerCase() || `[${id}]`}
{:else}
{$dictionary[category]?.[key] || `[${id}]`}
{/if}
{/key}
<!-- {#if $dictionary[category]?.[key]}
{pre}{$dictionary[category]?.[key]}{suf}
{:else if id.includes('.')}
{`${pre}[${id}]${suf}`}
{:else}
{id}
{/if} -->
105 changes: 55 additions & 50 deletions src/frontend/components/helpers/historyActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ export const historyActions = ({ obj, undo = null }: any) => {

let show = get(showsCache)[data.remember.showId]
if (!show) return
let previousShow: string = JSON.stringify(show)
let slides: any = show.slides || {}

let ref = _show(data.remember.showId).layouts([data.remember.layout]).ref()[0]
Expand All @@ -697,7 +698,7 @@ export const historyActions = ({ obj, undo = null }: any) => {
data.previousData = { template: show.settings.template, slides: clone(slides) }
let templateId: string = data.id

if (templateId) _show(data.remember.showId).set({ key: "settings.template", value: slideId ? null : templateId })
if (templateId && !slideId && show.settings?.template !== templateId) _show(data.remember.showId).set({ key: "settings.template", value: slideId ? null : templateId })

let template = clone(get(templates)[templateId])
updateSlidesWithTemplate(template)
Expand All @@ -717,66 +718,70 @@ export const historyActions = ({ obj, undo = null }: any) => {
else obj.newData = clone(data)

function updateSlidesWithTemplate(template: any) {
showsCache.update((a) => {
Object.entries(slides).forEach(([id, slide]: any) => {
if ((slideId && slideId !== id) || !slide) return

// show template
let slideTemplate = template
let isGlobalTemplate = true
// slide template
if (slide.settings?.template) {
slideTemplate = clone(get(templates)[slide.settings.template]) || template
Object.entries(slides).forEach(([id, slide]: any) => {
if ((slideId && slideId !== id) || !slide) return

// show template
let slideTemplate = template
let isGlobalTemplate = true
// slide template
if (slide.settings?.template) {
slideTemplate = clone(get(templates)[slide.settings.template]) || template
isGlobalTemplate = false
} else {
// group template
let isChild = slide.group === null
let globalGroup = slide.globalGroup
if (isChild) {
let parent = Object.values(show.slides).find((a) => a.children?.includes(id))
globalGroup = parent?.globalGroup
}
if (globalGroup && get(groups)[globalGroup]?.template) {
slideTemplate = clone(get(templates)[get(groups)[globalGroup]?.template]) || template
isGlobalTemplate = false
} else {
// group template
let isChild = slide.group === null
let globalGroup = slide.globalGroup
if (isChild) {
let parent = Object.values(a[data.remember.showId].slides).find((a) => a.children?.includes(id))
globalGroup = parent?.globalGroup
}
if (globalGroup && get(groups)[globalGroup]?.template) {
slideTemplate = clone(get(templates)[get(groups)[globalGroup]?.template]) || template
isGlobalTemplate = false
}
}
}

if (!slideTemplate?.items?.length) return
if (!slideTemplate?.items?.length) return

// roll items around
if (createItems && !slide.settings?.template) slide.items = [...slide.items.slice(1), slide.items[0]].filter((a) => a)
// roll items around
if (createItems && !slide.settings?.template) slide.items = [...slide.items.slice(1), slide.items[0]].filter((a) => a)

let changeOverflowItems = slide.settings?.template || createItems
let newItems = mergeWithTemplate(slide.items, slideTemplate.items, changeOverflowItems, obj.save !== false)
let changeOverflowItems = slide.settings?.template || createItems
let newItems = mergeWithTemplate(slide.items, slideTemplate.items, changeOverflowItems, obj.save !== false)

// remove items if not in template (and textbox is empty)
if (changeOverflowItems) {
let templateItemCount = getItemsCountByType(slideTemplate.items)
let slideItemCount = getItemsCountByType(newItems)
newItems = newItems.filter((a) => {
let type = a.type || "text"
if (templateItemCount[type] - slideItemCount[type] >= 0) return true
if (type === "text" && !isEmptyOrSpecial(a)) return true
// remove items if not in template (and textbox is empty)
if (changeOverflowItems) {
let templateItemCount = getItemsCountByType(slideTemplate.items)
let slideItemCount = getItemsCountByType(newItems)
newItems = newItems.filter((a) => {
let type = a.type || "text"
if (templateItemCount[type] - slideItemCount[type] >= 0) return true
if (type === "text" && !isEmptyOrSpecial(a)) return true

// remove item
slideItemCount[type]--
return false
})
}
// remove item
slideItemCount[type]--
return false
})
}

a[data.remember.showId].slides[id].items = clone(newItems)
show.slides[id].items = clone(newItems)

if (!isGlobalTemplate) return
if (!isGlobalTemplate) return

// set custom values
let isFirst = !!Object.values(a[data.remember.showId].layouts).find((layout) => layout.slides[0]?.id === id)
a[data.remember.showId].slides[id] = updateSlideFromTemplate(a[data.remember.showId].slides[id], slideTemplate, isFirst, changeOverflowItems)
let newLayoutData = updateLayoutsFromTemplate(a[data.remember.showId].layouts, a[data.remember.showId].media, slideTemplate, changeOverflowItems)
a[data.remember.showId].layouts = newLayoutData.layouts
a[data.remember.showId].media = newLayoutData.media
})
// set custom values
let isFirst = !!Object.values(show.layouts).find((layout) => layout.slides[0]?.id === id)
show.slides[id] = updateSlideFromTemplate(show.slides[id], slideTemplate, isFirst, changeOverflowItems)
let newLayoutData = updateLayoutsFromTemplate(show.layouts, show.media, slideTemplate, changeOverflowItems)
show.layouts = newLayoutData.layouts
show.media = newLayoutData.media
})

// don't update if show has not changed
if (obj.save === false && JSON.stringify(show) === previousShow) return

showsCache.update((a) => {
a[data.remember.showId] = show
return a
})
}
Expand Down
14 changes: 8 additions & 6 deletions src/frontend/components/helpers/media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,24 +217,26 @@ export function captureCanvas(data: any) {

// wait until loaded
let hasLoaded = await waitUntilValueIsDefined(() => (isImage ? mediaElem.complete : mediaElem.readyState === 4), 20)
if (!hasLoaded) return

console.log(data.input, hasLoaded)
if (!hasLoaded) {
send(MAIN, ["SAVE_IMAGE"], { path: data.output })
return
}

await wait(50)
captureCanvas(mediaElem, mediaSize)
})

async function captureCanvas(media, mediaSize) {
let ctx = canvas.getContext("2d")
if (!ctx) return
if (!ctx) {
send(MAIN, ["SAVE_IMAGE"], { path: data.output })
return
}

ctx.drawImage(media, 0, 0, mediaSize.width, mediaSize.height, 0, 0, canvas.width, canvas.height)
await wait(50)
let dataURL = canvas.toDataURL("image/jpeg", jpegQuality)

console.log(dataURL)

send(MAIN, ["SAVE_IMAGE"], { path: data.output, base64: dataURL })
}
}
Expand Down
1 change: 1 addition & 0 deletions src/frontend/components/helpers/setShow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export async function loadShows(s: string[]) {
let listenerId = uid()
window.api.receive(SHOW, receiveShow, listenerId)
function receiveShow(msg: any) {
if (!s.includes(msg.id)) return
count++

// prevent receiving multiple times
Expand Down
4 changes: 2 additions & 2 deletions src/frontend/components/helpers/showActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { get } from "svelte/store"
import { MAIN, OUTPUT } from "../../../types/Channels"
import type { OutSlide, Slide } from "../../../types/Show"
import { send } from "../../utils/request"
import { runAction } from "../actions/actions"
import { runAction, slideHasAction } from "../actions/actions"
import type { API_output_style } from "../actions/api"
import { playPauseGlobal } from "../drawer/timers/timers"
import {
Expand Down Expand Up @@ -411,7 +411,7 @@ export function updateOut(showId: string, index: number, layout: any, extra: boo
if (!background) {
layout.forEach((a, i) => {
if (i <= index && !a.data.disabled) {
if (a.data.actions?.clearBackground) background = null
if (slideHasAction(a.data?.actions, "clear_background")) background = null
else if (a.data.background) background = a.data.background
if (a.data.background && _show(showId).get("media")[a.data.background]?.loop === false) background = null
}
Expand Down
Loading

0 comments on commit 51597f8

Please sign in to comment.