From dd2c324f7d0226ad237d22c3e6e5fffd7cebbb6a Mon Sep 17 00:00:00 2001 From: Kristoffer Date: Mon, 9 Dec 2024 15:34:38 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20Media=20tags=20-=20Open?= =?UTF-8?q?Song=20HTML=20format=20importing=20-=20Fixed=20AudioStreams=20n?= =?UTF-8?q?ot=20starting=20from=20actions=20-=20Fixed=20playlist=20crossfa?= =?UTF-8?q?ding=20when=20time=20was=200=20-=20Performance=20alert=20when?= =?UTF-8?q?=20enabling=20screen=20capture=20-=20Fixed=20tag=20filter=20act?= =?UTF-8?q?ive=20after=20tag=20deleted=20-=20Fixed=20audio=20transition=20?= =?UTF-8?q?if=20played=20while=20clear=20audio=20action=20was=20triggered?= =?UTF-8?q?=20-=20UI=20tweaks=20-=20Updated=20languages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/import-logos/verseview.webp | Bin 40870 -> 16442 bytes public/lang/en.json | 4 +- public/lang/pt_BR.json | 37 +- public/lang/sk.json | 516 +++++++++++++++--- src/electron/data/defaults.ts | 1 + .../components/actions/CreateAction.svelte | 4 +- src/frontend/components/actions/api.ts | 2 +- .../components/context/ContextItem.svelte | 2 +- .../components/context/ContextMenu.svelte | 1 + .../components/context/contextMenus.ts | 7 +- src/frontend/components/context/loadItems.ts | 16 +- src/frontend/components/context/menuClick.ts | 40 ++ .../components/draw/DrawSettings.svelte | 86 ++- src/frontend/components/draw/Paint.svelte | 4 +- .../components/drawer/media/Media.svelte | 118 ++-- .../components/drawer/media/MediaCard.svelte | 68 ++- src/frontend/components/helpers/audio.ts | 9 +- .../components/helpers/historyHelpers.ts | 4 + src/frontend/components/helpers/media.ts | 2 + src/frontend/components/helpers/output.ts | 10 +- src/frontend/components/inputs/Color.svelte | 3 +- .../components/main/popups/ManageTags.svelte | 96 ++++ .../main/popups/SlideShortcut.svelte | 2 +- src/frontend/components/output/clear.ts | 2 +- .../output/preview/ClearButtons.svelte | 2 +- .../components/settings/tabs/Groups.svelte | 15 +- .../components/settings/tabs/Outputs.svelte | 6 +- .../components/settings/tabs/Theme.svelte | 12 +- .../components/slide/views/Timer.svelte | 2 +- src/frontend/converters/opensong.ts | 53 +- src/frontend/stores.ts | 6 +- src/frontend/utils/controllerTalk.ts | 2 +- src/frontend/utils/popup.ts | 2 + src/frontend/utils/save.ts | 5 +- src/frontend/utils/shortcuts.ts | 2 +- src/frontend/utils/updateSettings.ts | 4 +- src/types/Main.ts | 2 + src/types/Save.ts | 1 + src/types/Show.ts | 5 + 39 files changed, 947 insertions(+), 206 deletions(-) create mode 100644 src/frontend/components/main/popups/ManageTags.svelte diff --git a/public/import-logos/verseview.webp b/public/import-logos/verseview.webp index 8d50fd06d384a43549362641a52d922f4aeaf39d..f9020de51899ab60d1a52b91022f2e0d91bde8ef 100644 GIT binary patch literal 16442 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%0A;k3VTkhk{8g-2td%}o~=IdIn+ii$g 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 , change_volume: (data: API_volume) => updateVolume(data.volume ?? data.gain, data.gain !== undefined), // BC - start_audio_stream: (data: API_id) => startAudioStream(data.id), + start_audio_stream: (data: API_id) => startAudioStream(data), start_playlist: (data: API_id) => startPlaylist(data.id), playlist_next: () => audioPlaylistNext(), start_metronome: (data: API_metronome) => startMetronome(data), diff --git a/src/frontend/components/context/ContextItem.svelte b/src/frontend/components/context/ContextItem.svelte index b39b9ad9..62c83536 100644 --- a/src/frontend/components/context/ContextItem.svelte +++ b/src/frontend/components/context/ContextItem.svelte @@ -218,7 +218,7 @@ // don't hide context menu const keepOpen = ["uppercase", "lowercase", "capitalize", "trim"] // "dynamic_values" (caret position is lost) if (keepOpen.includes(id)) return - const keepOpenToggle = ["enabled_drawer_tabs", "tag_set", "tag_filter", "bind_slide", "bind_item"] + const keepOpenToggle = ["enabled_drawer_tabs", "tag_set", "tag_filter", "media_tag_set", "media_tag_filter", "bind_slide", "bind_item"] if (keepOpenToggle.includes(id)) { enabled = !enabled return diff --git a/src/frontend/components/context/ContextMenu.svelte b/src/frontend/components/context/ContextMenu.svelte index f48e0d04..5741a386 100644 --- a/src/frontend/components/context/ContextMenu.svelte +++ b/src/frontend/components/context/ContextMenu.svelte @@ -95,6 +95,7 @@ if (id === "format") return $contextData.textContent || $activePage !== "show" if (id === "remove_layers") return $contextData.layers if (id === "tag_set" || id === "tag_filter") return $contextData.tags + if (id === "media_tag_filter") return $contextData.media_tags return true } diff --git a/src/frontend/components/context/contextMenus.ts b/src/frontend/components/context/contextMenus.ts index 5e61c4e5..0597737c 100644 --- a/src/frontend/components/context/contextMenus.ts +++ b/src/frontend/components/context/contextMenus.ts @@ -42,6 +42,8 @@ export const contextMenuItems: { [key: string]: ContextMenuItem } = { enabledTabs: { label: "context.enabledTabs", items: ["LOAD_enabled_drawer_tabs"] }, tag_set: { label: "context.setTag", icon: "tag", items: ["LOAD_tag_set"] }, tag_filter: { label: "context.filterByTags", icon: "tag", items: ["LOAD_tag_filter"] }, + media_tag_set: { label: "context.setTag", icon: "tag", items: ["LOAD_media_tag_set"] }, + media_tag_filter: { label: "context.filterByTags", icon: "tag", items: ["LOAD_media_tag_filter"] }, newCategory: { label: "context.newCategory", icon: "add" }, newScripture: { label: "new.scripture", icon: "add" }, createCollection: { label: "new.collection", icon: "collection" }, @@ -198,7 +200,8 @@ export const contextMenuLayouts: { [key: string]: string[] } = { midi: ["play", "SEPERATOR", "edit", "delete"], // , "addToShow" // show_in_explorer!! - media_card: ["addToProject", "SEPERATOR", "edit", "preview", "favourite", "SEPERATOR", "play_no_audio", "play_no_filters", "SEPERATOR", "system_open"], + media: ["media_tag_filter"], + media_card: ["addToProject", "SEPERATOR", "edit", "preview", "favourite", "SEPERATOR", "play_no_audio", "play_no_filters", "SEPERATOR", "media_tag_set", "media_tag_filter", "SEPERATOR", "system_open"], // "addToFirstSlide", overlay_card: ["edit", "preview", "SEPERATOR", "lock_to_output", "place_under_slide", "SEPERATOR", "rename", "recolor", "duplicate", "delete"], // "addToShow", @@ -242,7 +245,7 @@ export const contextMenuLayouts: { [key: string]: string[] } = { // SHOWS // , "copy", "paste" - slide: ["slideGroups", "actions", "bind_to", "format", "remove_layers", "slide_transition", "disable", "edit", "SEPERATOR", "duplicate", "delete_slide", "remove_slide"], + slide: ["edit", "SEPERATOR", "slideGroups", "actions", "bind_to", "format", "remove_layers", "slide_transition", "disable", "SEPERATOR", "duplicate", "delete_slide", "remove_slide"], slideChild: ["slideGroups", "actions", "bind_to", "format", "remove_layers", "slide_transition", "disable", "edit", "SEPERATOR", "duplicate", "delete_slide", "remove_slide"], slideFocus: ["editSlideText"], group: ["rename", "recolor", "SEPERATOR", "selectAll", "SEPERATOR", "duplicate", "delete_group"], diff --git a/src/frontend/components/context/loadItems.ts b/src/frontend/components/context/loadItems.ts index 93afde4e..457799ad 100644 --- a/src/frontend/components/context/loadItems.ts +++ b/src/frontend/components/context/loadItems.ts @@ -1,5 +1,5 @@ import { get } from "svelte/store" -import { activeEdit, activeTagFilter, contextData, drawerTabsData, globalTags, groups, outputs, overlays, selected, shows, sorted } from "../../stores" +import { activeEdit, activeMediaTagFilter, activeTagFilter, contextData, drawerTabsData, globalTags, groups, media, mediaTags, outputs, overlays, selected, shows, sorted } from "../../stores" import { translate } from "../../utils/language" import { drawerTabs } from "../../values/tabs" import { actionData } from "../actions/actionData" @@ -33,6 +33,19 @@ const loadActions = { setContextData("tags", sortedTags.length) return sortedTags }, + media_tag_set: () => { + let selectedTags = get(media)[get(selected).data[0]?.path]?.tags || [] + let sortedTags = sortObject(sortByName(keysToID(get(mediaTags))), "color").map((a) => ({ ...a, label: a.name, enabled: selectedTags.includes(a.id), translate: false })) + const create = {label: "popup.manage_tags", icon: "edit", id: "create"} + if (sortedTags.length) sortedTags.push("SEPERATOR") + sortedTags.push(create) + return sortedTags + }, + media_tag_filter: () => { + let sortedTags = sortObject(sortByName(keysToID(get(mediaTags))), "color").map((a) => ({ ...a, label: a.name, enabled: get(activeMediaTagFilter).includes(a.id), translate: false })) + setContextData("media_tags", sortedTags.length) + return sortedTags + }, sort_shows: (items: ContextMenuItem[]) => sortItems(items, "shows"), sort_projects: (items: ContextMenuItem[]) => sortItems(items, "projects"), slide_groups: (items: ContextMenuItem[]) => { @@ -53,6 +66,7 @@ const loadActions = { let slideActions = [ { id: "action", label: "midi.start_action", icon: "actions" }, + "SEPERATOR", { id: "slide_shortcut", label: "actions.play_with_shortcut", icon: "play", enabled: currentActions?.slide_shortcut || false }, { id: "receiveMidi", label: "actions.play_on_midi", icon: "play", enabled: currentActions?.receiveMidi || false }, "SEPERATOR", diff --git a/src/frontend/components/context/menuClick.ts b/src/frontend/components/context/menuClick.ts index 6001ecab..b55b481f 100644 --- a/src/frontend/components/context/menuClick.ts +++ b/src/frontend/components/context/menuClick.ts @@ -9,6 +9,7 @@ import { activeDrawerTab, activeEdit, activeFocus, + activeMediaTagFilter, activePage, activePopup, activeRecording, @@ -17,6 +18,7 @@ import { activeTagFilter, audioFolders, categories, + contextActive, currentOutputSettings, currentWindow, dataPath, @@ -286,6 +288,44 @@ const actions: any = { activeTagFilter.set(activeTags || []) }, + media_tag_set: (obj: any) => { + let tagId = obj.menu.id + if (tagId === "create") { + contextActive.set(false) + popupData.set({type: "media"}) + activePopup.set("manage_tags") + return + } + + let disable = get(media)[get(selected).data[0]?.path]?.tags?.includes(tagId) + + obj.sel.data?.forEach(({ path }) => { + let tags = get(media)[path]?.tags || [] + + let existingIndex = tags.indexOf(tagId) + if (disable) { + if (existingIndex > -1) tags.splice(existingIndex, 1) + } else { + if (existingIndex < 0) tags.push(tagId) + } + + media.update((a) => { + if (!a[path]) a[path] = {} + a[path].tags = tags + return a + }) + }) + }, + media_tag_filter: (obj: any) => { + let tagId = obj.menu.id + + let activeTags = get(activeMediaTagFilter) + let currentIndex = activeTags.indexOf(tagId) + if (currentIndex < 0) activeTags.push(tagId) + else activeTags.splice(currentIndex, 1) + + activeMediaTagFilter.set(activeTags || []) + }, addToProject: (obj: any) => { if ((obj.sel.id !== "show" && obj.sel.id !== "show_drawer" && obj.sel.id !== "player" && obj.sel.id !== "media" && obj.sel.id !== "audio") || !get(activeProject)) return diff --git a/src/frontend/components/draw/DrawSettings.svelte b/src/frontend/components/draw/DrawSettings.svelte index 0823a7bd..b354ca86 100644 --- a/src/frontend/components/draw/DrawSettings.svelte +++ b/src/frontend/components/draw/DrawSettings.svelte @@ -78,35 +78,41 @@
{#key $drawTool} -
- {#key $drawSettings} - {#if $drawSettings[$drawTool]} - {#each Object.entries($drawSettings[$drawTool]) as [key, value]} - {#if key !== "clear" && (key !== "hold" || $drawTool !== "paint")} - - {#if key !== "clear" && (key !== "hold" || $drawTool !== "paint")} -

- {/if} - {#if key === "color"} - change(e, key)} style="width: 100%;" /> - {:else if ["glow", "hold", "rainbow", "hollow", "dots", "threed"].includes(key)} -
- check(e, key)} /> -
- {:else if key === "opacity"} - change(e, key)} /> - {:else if key === "radius"} - change(e, key)} /> - {:else if key !== "clear" && key !== "hold"} - change(e, key)} /> - {:else} -
- {/if} -
- {/if} - {/each} - {/if} - {/key} +
+ + +
+ +
+ {#key $drawSettings} + {#if $drawSettings[$drawTool]} + {#each Object.entries($drawSettings[$drawTool]) as [key, value]} + {#if key !== "clear" && (key !== "hold" || $drawTool !== "paint")} + + {#if key !== "clear" && (key !== "hold" || $drawTool !== "paint")} +

+ {/if} + {#if key === "color"} + change(e, key)} style="width: 100%;" /> + {:else if ["glow", "hold", "rainbow", "hollow", "dots", "threed"].includes(key)} +
+ check(e, key)} /> +
+ {:else if key === "opacity"} + change(e, key)} /> + {:else if key === "radius"} + change(e, key)} /> + {:else if key !== "clear" && key !== "hold"} + change(e, key)} /> + {:else} +
+ {/if} +
+ {/if} + {/each} + {/if} + {/key} +
{/key}
@@ -134,15 +140,35 @@ height: 100%; } + h6 { + display: flex; + align-items: center; + justify-content: center; + + font-weight: 600; + letter-spacing: 0.5px; + + padding: 0.3em 0.5em; + background-color: var(--primary-darkest); + border-radius: var(--border-radius); + + /* font-size: 0.9em; */ + text-transform: none !important; + margin: 0 !important; + } + .padding { display: flex; flex-direction: column; overflow-y: auto; overflow-x: hidden; - padding: 10px; height: 100%; } + .options { + padding: 10px; + } + .bottom { display: flex; flex-direction: column; diff --git a/src/frontend/components/draw/Paint.svelte b/src/frontend/components/draw/Paint.svelte index b70b1142..aff2dcb5 100644 --- a/src/frontend/components/draw/Paint.svelte +++ b/src/frontend/components/draw/Paint.svelte @@ -96,7 +96,7 @@ x: x, y: y, size: settings.size || 10, - color: settings.color || "white", + color: settings.color || "#ffffff", } lines.push(line) paintCache.set(lines) @@ -114,7 +114,7 @@ // ctx.moveTo(previousPos.x, previousPos.y) ctx.lineWidth = settings.size || 10 ctx.lineCap = "round" - ctx.strokeStyle = settings.color || "white" + ctx.strokeStyle = settings.color || "#ffffff" } else { previousPos = null if (lines.length && lines[lines.length - 1] !== "mouseup") lines.push("mouseup") diff --git a/src/frontend/components/drawer/media/Media.svelte b/src/frontend/components/drawer/media/Media.svelte index dd2116ed..c51ec9d1 100644 --- a/src/frontend/components/drawer/media/Media.svelte +++ b/src/frontend/components/drawer/media/Media.svelte @@ -4,7 +4,25 @@ import { slide } from "svelte/transition" import { uid } from "uid" import { MAIN, READ_FOLDER } from "../../../../types/Channels" - import { activeDrawerOnlineTab, activeEdit, activeFocus, activePopup, activeShow, dictionary, focusMode, labelsDisabled, media, mediaFolders, mediaOptions, outLocked, outputs, popupData, selectAllMedia, selected } from "../../../stores" + import { + activeDrawerOnlineTab, + activeEdit, + activeFocus, + activeMediaTagFilter, + activePopup, + activeShow, + dictionary, + focusMode, + labelsDisabled, + media, + mediaFolders, + mediaOptions, + outLocked, + outputs, + popupData, + selectAllMedia, + selected, + } from "../../../stores" import { destroy, send } from "../../../utils/request" import Icon from "../../helpers/Icon.svelte" import T from "../../helpers/T.svelte" @@ -33,7 +51,8 @@ let files: any[] = [] - let notFolders = ["all", "favourites", "online", "screens", "cameras"] + let specialTabs = ["online", "screens", "cameras"] + let notFolders = ["all", ...specialTabs] $: rootPath = notFolders.includes(active || "") ? "" : active !== null ? $mediaFolders[active]?.path! || "" : "" $: path = notFolders.includes(active || "") ? "" : rootPath @@ -137,7 +156,7 @@ // filter files let activeView: "all" | "folder" | "image" | "video" = "all" let filteredFiles: any[] = [] - $: if (activeView) filterFiles() + $: if (activeView || $activeMediaTagFilter) filterFiles() $: if (searchValue !== undefined) filterSearch() function filterFiles() { @@ -147,6 +166,11 @@ if (activeView === "all") filteredFiles = files.filter((a) => active !== "all" || !a.folder) else filteredFiles = files.filter((a) => (activeView === "folder" && active !== "all" && a.folder) || (!a.folder && activeView === getMediaType(a.extension))) + // filter by tag + if ($activeMediaTagFilter.length) { + filteredFiles = filteredFiles.filter((a) => !a.folder && $media[a.path]?.tags?.length && !$activeMediaTagFilter.find((tagId) => !$media[a.path].tags!.includes(tagId))) + } + // reset arrow selector loadAllFiles(filteredFiles) @@ -311,49 +335,53 @@ /> {:else if fullFilteredFiles.length} - {#key fullFilteredFiles} - {#if $mediaOptions.mode === "grid"} - - {#if item.folder} - - {:else} - ({ ...a, type: getMediaType(a.extension), name: removeExtension(a.name) }))} - bind:activeFile - {allFiles} - {active} - /> - {/if} - - {:else} - - {#if file.folder} - - {:else} - ({ ...a, type: getMediaType(a.extension), name: removeExtension(a.name) }))} - bind:activeFile - {allFiles} - {active} - /> - {/if} - - {/if} - {/key} +
+ {#key fullFilteredFiles} + {#if $mediaOptions.mode === "grid"} + + {#if item.folder} + + {:else} + ({ ...a, type: getMediaType(a.extension), name: removeExtension(a.name) }))} + bind:activeFile + {allFiles} + {active} + /> + {/if} + + {:else} + + {#if file.folder} + + {:else} + ({ ...a, type: getMediaType(a.extension), name: removeExtension(a.name) }))} + bind:activeFile + {allFiles} + {active} + /> + {/if} + + {/if} + {/key} +
{:else} -
- -
+
+
+ +
+
{/if} diff --git a/src/frontend/components/drawer/media/MediaCard.svelte b/src/frontend/components/drawer/media/MediaCard.svelte index 1ca86198..ecbc576b 100644 --- a/src/frontend/components/drawer/media/MediaCard.svelte +++ b/src/frontend/components/drawer/media/MediaCard.svelte @@ -1,10 +1,11 @@ @@ -127,6 +139,22 @@ on:mouseleave={() => (hover = false)} on:mousemove={move} > + +
+ {#if tags.length} +
+
+ +
+ +

{tags.length === 1 ? $mediaTags[tags[0]]?.name || "—" : tags.length}

+
+
+ {/if} +
+ {#if thumbnail} {:else} @@ -149,4 +177,38 @@ .icon :global(svg) { height: 100%; } + + /* icons */ + + .icons { + pointer-events: none; + display: flex; + flex-direction: column; + position: absolute; + left: 0; + z-index: 1; + font-size: 0.9em; + + height: 80%; + flex-wrap: wrap; + + max-width: calc(100% - 21px); + } + .icons div { + opacity: 0.9; + display: flex; + } + .icons .button { + background-color: rgb(0 0 0 / 0.6); + pointer-events: all; + } + .icons span { + pointer-events: all; + background-color: rgb(0 0 0 / 0.6); + padding: 3px; + font-size: 0.75em; + font-weight: bold; + display: flex; + align-items: center; + } diff --git a/src/frontend/components/helpers/audio.ts b/src/frontend/components/helpers/audio.ts index bbec8dcd..46cfea5a 100644 --- a/src/frontend/components/helpers/audio.ts +++ b/src/frontend/components/helpers/audio.ts @@ -13,7 +13,7 @@ import { checkNextAfterMedia } from "./showActions" // WIP use get(special).audio_fade_duration ?? 1.5 to fade in when starting song ?? (currently just when fading out) -export async function playAudio({ path, name = "", audio = null, stream = null }: any, pauseIfPlaying: boolean = true, startAt: number = 0, playMultiple: boolean = false, crossfade: number = 0) { +export async function playAudio({ path, name = "", audio = null, stream = null }: any, pauseIfPlaying: boolean = true, startAt: number = 0, playMultiple: boolean = false, crossfade: number = 0, playlistCrossfade: boolean = false) { let existing: any = get(playingAudio)[path] if (existing) { if (!pauseIfPlaying) { @@ -36,7 +36,7 @@ export async function playAudio({ path, name = "", audio = null, stream = null } let audioPlaying = Object.keys(get(playingAudio)).length if (crossfade) crossfadeAudio(crossfade) - else if (!playMultiple) clearAudio("", false) + else if (!playMultiple) clearAudio("", false, playlistCrossfade) let encodedPath = encodeFilePath(path) audio = audio || new Audio(encodedPath) @@ -252,7 +252,7 @@ export function playlistNext(previous: string = "", specificSong: string = "", c }) // if (crossfade) isCrossfading = true - playAudio({ path: nextSong }, false, 0, false, crossfade) + playAudio({ path: nextSong }, false, 0, false, crossfade, true) function getSongs(): string[] { if (previous && get(activePlaylist)?.songs) return get(activePlaylist).songs @@ -569,7 +569,7 @@ function getHighestNumber(numbers: number[]): number { let clearing = false let forceClear: boolean = false -export function clearAudio(path: string = "", clearPlaylist: boolean = true, playlistCrossfade: boolean = false) { +export function clearAudio(path: string = "", clearPlaylist: boolean = true, playlistCrossfade: boolean = false, commonClear: boolean = false) { // turn off any playlist if (clearPlaylist && (!path || get(activePlaylist)?.active === path)) activePlaylist.set(null) @@ -579,6 +579,7 @@ export function clearAudio(path: string = "", clearPlaylist: boolean = true, pla const clearTime = playlistCrossfade ? 0 : (get(special).audio_fade_duration ?? 1.5) if (clearing) { + if (!commonClear) return // force stop audio files (bypass timeout if already active) forceClear = true setTimeout(() => (forceClear = false), 100) diff --git a/src/frontend/components/helpers/historyHelpers.ts b/src/frontend/components/helpers/historyHelpers.ts index 16941c91..4a6c79a4 100644 --- a/src/frontend/components/helpers/historyHelpers.ts +++ b/src/frontend/components/helpers/historyHelpers.ts @@ -7,6 +7,7 @@ import { activeRename, activeShow, activeStage, + activeTagFilter, audioPlaylists, currentOutputSettings, dictionary, @@ -440,6 +441,9 @@ export const _updaters = { activeRename.set("tag_" + id) return data }, + deselect: () => { + activeTagFilter.set([]) + } }, tag_key: { store: globalTags }, diff --git a/src/frontend/components/helpers/media.ts b/src/frontend/components/helpers/media.ts index ca2d2854..6994bd50 100644 --- a/src/frontend/components/helpers/media.ts +++ b/src/frontend/components/helpers/media.ts @@ -60,6 +60,8 @@ export function joinPath(path: string[]): string { // fix for media files with special characters in file name not playing export function encodeFilePath(path: string): string { + if (!path) return "" + // already encoded if (path.match(/%\d+/g) || path.includes("http") || path.includes("data:")) return path diff --git a/src/frontend/components/helpers/output.ts b/src/frontend/components/helpers/output.ts index 38f96dfe..e5243549 100644 --- a/src/frontend/components/helpers/output.ts +++ b/src/frontend/components/helpers/output.ts @@ -41,6 +41,7 @@ import { fadeinAllPlayingAudio, fadeoutAllPlayingAudio } from "./audio" import { getExtension, getFileName, removeExtension } from "./media" import { replaceDynamicValues } from "./showActions" import { _show } from "./shows" +import { newToast } from "../../utils/common" export function displayOutputs(e: any = {}, auto: boolean = false) { // sort so display order can be changed! (needs app restart) @@ -318,12 +319,12 @@ export function getOutputResolution(outputId: string, _updater = get(outputs)) { return style || { width: 1920, height: 1080 } } -export function checkWindowCapture() { - getActiveOutputs(get(outputs), false, true, true).forEach(shouldBeCaptured) +export function checkWindowCapture(startup: boolean = false) { + getActiveOutputs(get(outputs), false, true, true).forEach((a) => shouldBeCaptured(a, startup)) } // NDI | OutputShow | Stage CurrentOutput -export function shouldBeCaptured(outputId: string) { +export function shouldBeCaptured(outputId: string, startup: boolean = false) { let output = get(outputs)[outputId] let captures: any = { ndi: !!output.ndi, @@ -331,6 +332,9 @@ export function shouldBeCaptured(outputId: string) { stage: stageHasOutput(outputId), } + // alert user that screen recording starts + if (!startup && Object.values(captures).filter(Boolean).length) newToast("$toast.output_capture_enabled") + send(OUTPUT, ["CAPTURE"], { id: outputId, captures }) } function stageHasOutput(outputId: string) { diff --git a/src/frontend/components/inputs/Color.svelte b/src/frontend/components/inputs/Color.svelte index c93cddbf..d814d561 100644 --- a/src/frontend/components/inputs/Color.svelte +++ b/src/frontend/components/inputs/Color.svelte @@ -11,6 +11,7 @@ export let enableNoColor: boolean = false export let showDisabled: boolean = false export let custom: boolean = false + export let rightAlign: boolean = false export let height: number = 0 export let width: number = 0 @@ -43,7 +44,7 @@ } let colorElem - let clipRight: boolean = false + let clipRight: boolean = rightAlign || false $: if (colorElem) { let pickerRect = colorElem.getBoundingClientRect() let pickerRight = pickerRect.left + 200 diff --git a/src/frontend/components/main/popups/ManageTags.svelte b/src/frontend/components/main/popups/ManageTags.svelte new file mode 100644 index 00000000..2e7df30c --- /dev/null +++ b/src/frontend/components/main/popups/ManageTags.svelte @@ -0,0 +1,96 @@ + + +
+ {#if tags.length} + {#each tags as tag} + + updateKey(e, tag.id, "name")} /> + updateKey(e, tag.id, "color")} rightAlign /> + + + + {/each} + {:else} +
+ +
+ {/if} + +
+ + + + +
+ + diff --git a/src/frontend/components/main/popups/SlideShortcut.svelte b/src/frontend/components/main/popups/SlideShortcut.svelte index ca4889e7..63cf6b0f 100644 --- a/src/frontend/components/main/popups/SlideShortcut.svelte +++ b/src/frontend/components/main/popups/SlideShortcut.svelte @@ -38,7 +38,7 @@ -

+

{#if currentShortcut}
diff --git a/src/frontend/components/output/clear.ts b/src/frontend/components/output/clear.ts index bb6b0926..2f20632a 100644 --- a/src/frontend/components/output/clear.ts +++ b/src/frontend/components/output/clear.ts @@ -41,7 +41,7 @@ export function clearAll(button: boolean = false) { clearBackground() clearSlide(true) clearOverlays() - clearAudio() + clearAudio("", true, false, true) clearTimers() } diff --git a/src/frontend/components/output/preview/ClearButtons.svelte b/src/frontend/components/output/preview/ClearButtons.svelte index 52db13ac..053d14f4 100644 --- a/src/frontend/components/output/preview/ClearButtons.svelte +++ b/src/frontend/components/output/preview/ClearButtons.svelte @@ -32,7 +32,7 @@ background: () => clearBackground(), slide: () => clearSlide(), overlays: () => clearOverlays(), - audio: () => clearAudio(), + audio: () => clearAudio("", true, false, true), nextTimer: () => clearTimers(), } diff --git a/src/frontend/components/settings/tabs/Groups.svelte b/src/frontend/components/settings/tabs/Groups.svelte index 659d85ba..ba41c024 100644 --- a/src/frontend/components/settings/tabs/Groups.svelte +++ b/src/frontend/components/settings/tabs/Groups.svelte @@ -88,6 +88,7 @@ special.update((a) => { delete a.numberKeys + delete a.autoLetterShortcut a.capitalize_words = "Jesus, Lord" // updateSettings.ts return a }) @@ -159,6 +160,7 @@ on:click={() => { history({ id: "UPDATE", newData: { id: group.id }, location: { page: "settings", id: "global_group" } }) }} + title={$dictionary.actions?.delete} > @@ -166,16 +168,19 @@ {/each} + + + +
-
diff --git a/src/frontend/components/settings/tabs/Outputs.svelte b/src/frontend/components/settings/tabs/Outputs.svelte index fa8eced4..cc7edb74 100644 --- a/src/frontend/components/settings/tabs/Outputs.svelte +++ b/src/frontend/components/settings/tabs/Outputs.svelte @@ -37,7 +37,7 @@ // auto revert special values if (autoRevert.includes(key) && value && !reverted.includes(key)) { - newToast($dictionary.toast?.reverting_setting?.replace("{}", revertTime.toString())) + newToast($dictionary.toast?.reverting_setting?.replace("{}", revertTime.toString()) || "") reverted.push(key) setTimeout(() => { updateOutput(key, false, outputId) @@ -45,7 +45,9 @@ }, revertTime * 1000) } - if (key === "blackmagic") { + if (key === "ndi") { + if (value) newToast("$toast.output_capture_enabled") + } else if (key === "blackmagic") { if (value === true) { // send(BLACKMAGIC, ["GET_DEVICES"]) updateOutput("transparent", true) diff --git a/src/frontend/components/settings/tabs/Theme.svelte b/src/frontend/components/settings/tabs/Theme.svelte index eae80ea2..d93f938c 100644 --- a/src/frontend/components/settings/tabs/Theme.svelte +++ b/src/frontend/components/settings/tabs/Theme.svelte @@ -22,8 +22,8 @@ "primary-darker", "primary-darkest", "secondary", - "secondary-text", "text", + "secondary-text", // "textInvert", // "secondary-opacity", // "hover", @@ -160,10 +160,12 @@ - + {#if Object.values($themes).length < 10} + + {/if}
diff --git a/src/frontend/components/slide/views/Timer.svelte b/src/frontend/components/slide/views/Timer.svelte index c898d767..7bc673a6 100644 --- a/src/frontend/components/slide/views/Timer.svelte +++ b/src/frontend/components/slide/views/Timer.svelte @@ -30,7 +30,7 @@ $: min = Math.min(timer.start || 0, timer.end || 0) $: max = Math.max(timer.start || 0, timer.end || 0) $: percentage = Math.max(0, Math.min(100, ((currentTime - min) / (max - min)) * 100)) - $: itemColor = getStyles(item?.style)?.color || "white" + $: itemColor = getStyles(item?.style)?.color || "#ffffff" $: overflow = getTimerOverflow(currentTime) $: negative = timer?.start! > timer?.end! || currentTime < 0 diff --git a/src/frontend/converters/opensong.ts b/src/frontend/converters/opensong.ts index 243eee6e..d7d829e7 100644 --- a/src/frontend/converters/opensong.ts +++ b/src/frontend/converters/opensong.ts @@ -4,8 +4,8 @@ import { checkName, formatToFileName } from "../components/helpers/show" import type { Bible } from "./../../types/Bible" import { ShowObj } from "./../classes/Show" import { activePopup, alertMessage, dictionary, groups, scriptures, scripturesCache } from "./../stores" -import { createCategory, setTempShows } from "./importHelpers" import { setActiveScripture } from "./bible" +import { createCategory, setTempShows } from "./importHelpers" interface Song { title: string @@ -39,7 +39,9 @@ export function convertOpenSong(data: any) { setTimeout(() => { data?.forEach(({ content }: any) => { - let song = XMLtoObject(content) + let song: any = {} + if (content.includes("")) song = HTMLtoObject(content) + else song = XMLtoObject(content) console.log(song) let layoutID = uid() @@ -239,3 +241,50 @@ function XMLtoBible(xml: string): Bible { } const getChildren = (parent: any, name: string) => parent.getElementsByTagName(name) + +function HTMLtoObject(content: string) { + let parser = new DOMParser() + let html = parser.parseFromString(content, "text/html").children[0]?.querySelector("body") + + // WIP chords + + const groups = content.split('').slice(1) + let lyrics: string = "" + groups.forEach(group =>{ + let linesEnd = group.lastIndexOf("
") + let g = group.slice(0, linesEnd) + const lines = group.indexOf(" -1 ? g.split("').slice(1) + + let groupName = group.slice(0, group.indexOf("
")).trim() + lyrics += `[${groupName}]\n` + + lines.forEach(line => { + const sections = line.indexOf('class="lyrics">') > -1 ? line.split('class="lyrics">').slice(1) : [line] + + sections.forEach(section => { + let text = section.slice(0, section.indexOf("")) + lyrics += text + }) + + lyrics += "\n" + }) + + lyrics = lyrics.trim() + "\n\n" + }) + + lyrics = lyrics.trim() + + let object: Song = { + title: html?.querySelector("#title")?.textContent || "", + author: html?.querySelector("#author")?.textContent || "", + ccli: html?.querySelector("#ccli")?.textContent || "", + copyright: html?.querySelector("#copyright")?.textContent || "", + time_sig: html?.querySelector("#time_sig")?.textContent || "", + lyrics, + hymn_number: html?.querySelector("#hymn_number")?.textContent || "", + key: html?.querySelector("#key")?.textContent || "", + backgrounds: html?.querySelector("#backgrounds")?.textContent || "", + } + + return object +} diff --git a/src/frontend/stores.ts b/src/frontend/stores.ts index 3e907bea..b1dc8049 100644 --- a/src/frontend/stores.ts +++ b/src/frontend/stores.ts @@ -9,7 +9,7 @@ import type { Draw, DrawSettings, DrawTools } from "../types/Draw" import type { ActiveEdit, Media, MediaOptions, NumberObject, Popups, Selected, SlidesOptions } from "../types/Main" import type { Folders, Projects, ShowRef } from "../types/Projects" import type { Dictionary, Styles, Themes } from "../types/Settings" -import type { ID, MidiIn, Overlays, ShowList, Shows, Templates, Timer, Transition } from "../types/Show" +import type { ID, MidiIn, Overlays, ShowList, Shows, Tag, Templates, Timer, Transition } from "../types/Show" import type { ActiveStage, StageLayouts } from "../types/Stage" import type { BibleCategories, Categories, DrawerTabs, SettingsTabs, TopViews } from "../types/Tabs" import type { Channels, Playlist } from "./../types/Audio" @@ -60,6 +60,7 @@ export const activeAnimate: Writable = writable({ slide: -1, index: -1 }) export const allOutputs: Writable = writable({}) // stage data in output windows export const activeScripture: Writable = writable({}) export const activeTagFilter: Writable = writable([]) +export const activeMediaTagFilter: Writable = writable([]) export const activeTriggerFunction: Writable = writable("") export const guideActive: Writable = writable(false) export const runningActions: Writable = writable([]) @@ -167,7 +168,7 @@ export const transitionData: Writable<{ text: Transition; media: Transition }> = media: { type: "fade", duration: 800, easing: "sine" }, }) // {default} export const slidesOptions: Writable = writable({ columns: 4, mode: "grid" }) // {default} -export const globalTags: Writable<{ [key: string]: { name: string; color: string } }> = writable({}) // {} +export const globalTags: Writable<{ [key: string]: Tag }> = writable({}) // {} // PROJECT export const openedFolders: Writable = writable([]) // [] @@ -189,6 +190,7 @@ export const triggers: Writable<{ [key: string]: any }> = writable({}) // {} export const media: Writable = writable({}) // {} export const mediaFolders: Writable = writable({}) // {default} export const videoMarkers: Writable<{ [key: string]: { name: string; time: number }[] }> = writable({}) // {} +export const mediaTags: Writable<{ [key: string]: Tag }> = writable({}) // {} export const checkedFiles: Writable = writable([]) // OVERLAYS diff --git a/src/frontend/utils/controllerTalk.ts b/src/frontend/utils/controllerTalk.ts index 5a225d8c..371d5919 100644 --- a/src/frontend/utils/controllerTalk.ts +++ b/src/frontend/utils/controllerTalk.ts @@ -53,7 +53,7 @@ export const receiveCONTROLLER = { draw.set(data.offset) drawTool.set(tool) - if (tool === "paint") paintCache.set([{ x: 0, y: 0, size: 0, color: "white" }]) + if (tool === "paint") paintCache.set([{ x: 0, y: 0, size: 0, color: "#ffffff" }]) }, GET_OUTPUT_ID: () => { return { channel: "GET_OUTPUT_ID", data: get(serverData)?.output_stream?.outputId || getActiveOutputs(get(outputs), false, true, true)[0] } diff --git a/src/frontend/utils/popup.ts b/src/frontend/utils/popup.ts index 1aadff9c..6c850238 100644 --- a/src/frontend/utils/popup.ts +++ b/src/frontend/utils/popup.ts @@ -47,6 +47,7 @@ import Unsaved from "../components/main/popups/Unsaved.svelte" import Variable from "../components/main/popups/Variable.svelte" import { activePopup, popupData } from "../stores" import CategoryAction from "../components/main/popups/CategoryAction.svelte" +import ManageTags from "../components/main/popups/ManageTags.svelte" export const popups: { [key in Popups]: ComponentType } = { initialize: Initialize, @@ -82,6 +83,7 @@ export const popups: { [key in Popups]: ComponentType } = { animate: Animate, translate: Translate, next_timer: NextTimer, + manage_tags: ManageTags, advanced_settings: AdvancedScreen, about: About, shortcuts: Shortcuts, diff --git a/src/frontend/utils/save.ts b/src/frontend/utils/save.ts index 4580ed0c..a245189d 100644 --- a/src/frontend/utils/save.ts +++ b/src/frontend/utils/save.ts @@ -38,6 +38,7 @@ import { media, mediaFolders, mediaOptions, + mediaTags, metronome, midiIn, openedFolders, @@ -159,6 +160,7 @@ export function save(closeWhenFinished: boolean = false, customTriggers: { backu audioPlaylists: get(audioPlaylists), midiIn: get(midiIn), videoMarkers: get(videoMarkers), + mediaTags: get(mediaTags), customizedIcons: get(customizedIcons), companion: get(companion), globalTags: get(globalTags), @@ -217,7 +219,7 @@ export function saveComplete({ closeWhenFinished, customTriggers }: any) { if (customTriggers?.backup || customTriggers?.changeUserData) return let mainFolderId = get(driveData)?.mainFolderId - if (!mainFolderId || get(driveData)?.disabled === true) { + if (!mainFolderId || get(driveData)?.disabled === true || !Object.keys(get(driveKeys)).length) { if (closeWhenFinished) closeApp() return @@ -352,6 +354,7 @@ const saveList: { [key in SaveList]: any } = { gain: null, midiIn: midiIn, videoMarkers: videoMarkers, + mediaTags: mediaTags, customizedIcons: customizedIcons, driveKeys: driveKeys, driveData: driveData, diff --git a/src/frontend/utils/shortcuts.ts b/src/frontend/utils/shortcuts.ts index 881de1e6..311a93e4 100644 --- a/src/frontend/utils/shortcuts.ts +++ b/src/frontend/utils/shortcuts.ts @@ -217,7 +217,7 @@ export const previewShortcuts: any = { if (!get(outLocked)) setOutput("overlays", []) }, F4: () => { - if (!get(outLocked)) clearAudio() + if (!get(outLocked)) clearAudio("", true, false, true) }, F5: () => { if (!get(special).disablePresenterControllerKeys) nextSlideIndividual(null) diff --git a/src/frontend/utils/updateSettings.ts b/src/frontend/utils/updateSettings.ts index 7f2e550b..c1161137 100644 --- a/src/frontend/utils/updateSettings.ts +++ b/src/frontend/utils/updateSettings.ts @@ -37,6 +37,7 @@ import { lockedOverlays, mediaFolders, mediaOptions, + mediaTags, metronome, midiIn, openedFolders, @@ -120,7 +121,7 @@ export function updateSettings(data: any) { setTimeout(() => { restartOutputs() if (get(autoOutput)) setTimeout(() => displayOutputs({}, true), 500) - setTimeout(checkWindowCapture, 1000) + setTimeout(() => checkWindowCapture(true), 1000) }, 1500) } @@ -282,6 +283,7 @@ const updateList: { [key in SaveListSettings | SaveListSyncedSettings]: any } = gain: (v: any) => gain.set(v), midiIn: (v: any) => midiIn.set(v), videoMarkers: (v: any) => videoMarkers.set(v), + mediaTags: (v: any) => mediaTags.set(v), customizedIcons: (v: any) => customizedIcons.set(v), driveData: (v: any) => driveData.set(v), calendarAddShow: (v: any) => calendarAddShow.set(v), diff --git a/src/types/Main.ts b/src/types/Main.ts index 1975fa11..33463088 100644 --- a/src/types/Main.ts +++ b/src/types/Main.ts @@ -107,6 +107,7 @@ export interface MediaStyle { volume?: number // audio rendering?: string // image rendering info?: any // cached codec/mime data + tags?: string[] // media tags } export type Popups = @@ -143,6 +144,7 @@ export type Popups = | "animate" | "translate" | "next_timer" + | "manage_tags" | "advanced_settings" | "about" | "shortcuts" diff --git a/src/types/Save.ts b/src/types/Save.ts index 4e47d231..83000ffd 100644 --- a/src/types/Save.ts +++ b/src/types/Save.ts @@ -15,6 +15,7 @@ export type SaveListSyncedSettings = | "groups" | "midiIn" | "videoMarkers" + | "mediaTags" | "customizedIcons" | "companion" | "globalTags" diff --git a/src/types/Show.ts b/src/types/Show.ts index ac005b54..7fb599f2 100644 --- a/src/types/Show.ts +++ b/src/types/Show.ts @@ -364,6 +364,11 @@ export interface OutTransition { duration: number } +export interface Tag { + name: string + color: string +} + // types export type ID = string