Compare commits

...

16 Commits

Author SHA1 Message Date
WarmUpTill
7ae88f7560 Reset invalid transition behaviour settings 2023-01-28 12:42:32 -08:00
WarmUpTill
ae70af26d1 Add option to assign substring based on regex to variable 2023-01-28 12:42:32 -08:00
WarmUpTill
483bdc237c Add option to create partial matching RegexConf 2023-01-28 12:42:32 -08:00
WarmUpTill
2c564b47f4 Add option to assign substring of current value to a variable 2023-01-28 12:42:32 -08:00
WarmUpTill
fc80d0b5f3 Add option to round variable to nearest integer 2023-01-28 12:42:32 -08:00
WarmUpTill
d094c189d3 Handle invalid paths due to scene collection name in settings export 2023-01-28 12:42:32 -08:00
WarmUpTill
40d8819e77 Fix warnings 2023-01-28 12:42:32 -08:00
WarmUpTill
4a3d019f06 Remove workaround to avoid race conditions 2023-01-28 12:42:32 -08:00
WarmUpTill
5366a4a6ed Fix crash on exit if using scene condition
obs_source_get_name() returning nullptr was not handled
2023-01-28 12:42:32 -08:00
WarmUpTill
e8230d8e5b Fix themes displaying list item selections incorrectly
The issue was that the blue selection highlight was not visible and
instead, a grey box was painted around each item.
I am not sure what exactly was causing this.
2023-01-28 12:42:32 -08:00
WarmUpTill
ebdbb9011f Fix scene switch action aborting macro execution
abortMacroWait was not reset in waitForTransitionChangeFixedDuration()
leading to the scene switch action returning false
2023-01-28 12:42:32 -08:00
BlackScreen
e43793354e Update german translation to the latest version 2023-01-27 12:32:03 -08:00
WarmUpTill
438c54599e Reduce time it takes to close preview dialog 2023-01-20 12:30:47 -08:00
WarmUpTill
da42183177 Fix VariableResolvingString returning empty string if no variables exist 2023-01-20 12:30:47 -08:00
WarmUpTill
295fa3f122 Fix crash on import 2023-01-20 12:30:47 -08:00
WarmUpTill
cb87f1cc36 Fix file condition always returning false 2023-01-18 07:49:21 -08:00
23 changed files with 987 additions and 85 deletions

View File

@@ -28,7 +28,10 @@ AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Nach Ausführen von Aktion
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="In diesem Zeitraum werden potentielle erfüllte Bedingungen ignoriert!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ausführliches Logging"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Fensterposition und -größe speichern"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Benachrichtigungen im System-Tray anzeigen"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deaktiviere UI Tipps"
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="Tabs verstecken, die in Makros repräsentiert sind"
AdvSceneSwitcher.generalTab.matchBehavior="Verhalten anpassen"
AdvSceneSwitcher.generalTab.priority="Priorität"
AdvSceneSwitcher.generalTab.priority.description="Szenenwechselmethoden sortiert nach Priorität"
AdvSceneSwitcher.generalTab.priority.threadPriority="Benutze Thread Priorität"
@@ -51,11 +54,542 @@ AdvSceneSwitcher.generalTab.priority.media="Medien"
AdvSceneSwitcher.generalTab.priority.time="Zeit"
AdvSceneSwitcher.generalTab.priority.audio="Audio"
AdvSceneSwitcher.generalTab.priority.video="Video"
AdvSceneSwitcher.generalTab.priority.macro="Makro"
AdvSceneSwitcher.generalTab.transition="Übergänge"
AdvSceneSwitcher.generalTab.setTransitionBy="Beim Ändern des Szenenübergangs:"
AdvSceneSwitcher.generalTab.transitionOverride="Verwende Übergangsüberschreibungen"
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Wechsle den aktiven Szenenübergangtyp"
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="Mindestens eine Option muss aktiv sein:\n\n - Verwende Übergangsüberschreibungen\n\n - Wechsle den aktiven Szenenübergangtyp"
; Macro Tab
AdvSceneSwitcher.macroTab.title="Makro"
AdvSceneSwitcher.macroTab.macros="Makros"
AdvSceneSwitcher.macroTab.priorityWarning="Hinweis: Es wird empfohlen, Makros als Funktion mit höchster Priorität zu konfigurieren.\nDiese Einstellung kann im Allgemein-Tab geändert werden."
AdvSceneSwitcher.macroTab.help="Mit Makros können eine Reihe von Aktionen in Abhängigkeit von mehreren Bedingungen ausgeführt werden.\n\nKlicke auf das hervorgehobene Plus-Symbol, um ein neues Makro hinzuzufügen."
AdvSceneSwitcher.macroTab.editConditionHelp="In diesem Abschnitt können Bedingungen für die Makros definiert werden.\n\nWähle auf der linken Seite ein vorhandenes Makro aus oder füge ein neues hinzu.\nKlicke dann auf die Plus-Schaltfläche unten, um eine neue Bedingung hinzuzufügen."
AdvSceneSwitcher.macroTab.editActionHelp="In diesem Abschnitt können Aktionen für die Makros definiert werden.\n\nWähle auf der linken Seite ein vorhandenes Makro aus oder füge ein neues hinzu.\nKlicke dann auf die Plus-Schaltfläche unten, um eine neue Aktion hinzuzufügen."
AdvSceneSwitcher.macroTab.edit="Makro bearbeiten"
AdvSceneSwitcher.macroTab.edit.logic="Logik-Typ:"
AdvSceneSwitcher.macroTab.edit.condition="Bedingungs-Typ:"
AdvSceneSwitcher.macroTab.edit.action="Aktions-Typ:"
AdvSceneSwitcher.macroTab.add="Neues Makro hinzufügen"
AdvSceneSwitcher.macroTab.name="Name:"
AdvSceneSwitcher.macroTab.run="Makro ausführen"
AdvSceneSwitcher.macroTab.runFail="Ausführen von \"%1\" fehlgeschlagen!\nEntweder ist eine der Aktionen fehlgeschlagen oder das Makro wird bereits ausgeführt."
AdvSceneSwitcher.macroTab.runInParallel="Parallel zu anderen Makros ausführen"
AdvSceneSwitcher.macroTab.onChange="Nur bei Änderung ausführen"
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
AdvSceneSwitcher.macroTab.defaultGroupName="Gruppe %1"
AdvSceneSwitcher.macroTab.exists="Makro-Name existiert bereits"
AdvSceneSwitcher.macroTab.groupDeleteConfirm="Sicher, dass \"%1\" und alle zugehörigen Elemente gelöscht werden?"
AdvSceneSwitcher.macroTab.copy="Kopie des aktuellen Makros erstellen"
AdvSceneSwitcher.macroTab.group="Ausgewählte Elemente gruppieren"
AdvSceneSwitcher.macroTab.ungroup="Gruppierung ausgewählter Gruppen aufheben"
AdvSceneSwitcher.macroTab.expandAll="Alle erweitern"
AdvSceneSwitcher.macroTab.collapseAll="Alle einklappen"
AdvSceneSwitcher.macroTab.maximize="Maximieren"
AdvSceneSwitcher.macroTab.minimize="Minimieren"
AdvSceneSwitcher.macroTab.highlightSettings="Visuelle Einstellungen"
AdvSceneSwitcher.macroTab.hotkeySettings="Hotkey-Einstellungen"
AdvSceneSwitcher.macroTab.highlightExecutedMacros="Kürzlich ausgeführte Makros hervorheben"
AdvSceneSwitcher.macroTab.highlightTrueConditions="Bedingungen des aktuell ausgewählten Makros hervorheben, die kürzlich als wahr bewertet wurden"
AdvSceneSwitcher.macroTab.highlightPerformedActions="Zuletzt ausgeführte Aktionen des aktuell ausgewählten Makros hervorheben"
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Hotkeys zur Steuerung des Pausen-Status neuer Makros registrieren"
AdvSceneSwitcher.macroTab.currentDisableHotkeys="Hotkeys zur Steuerung des Pausen-Status ausgewählter Makros registrieren"
; Macro List
AdvSceneSwitcher.macroList.deleted="gelöscht"
AdvSceneSwitcher.macroList.duplicate="\"%1\" ist bereits ausgewählt!"
; Macro Logic
AdvSceneSwitcher.logic.none="Eintrag ignorieren"
AdvSceneSwitcher.logic.and="Und"
AdvSceneSwitcher.logic.or="Oder"
AdvSceneSwitcher.logic.andNot="Und nicht"
AdvSceneSwitcher.logic.orNot="Oder nicht"
AdvSceneSwitcher.logic.rootNone="Wenn"
AdvSceneSwitcher.logic.not="Wenn nicht"
; Macro Conditions
AdvSceneSwitcher.condition.audio="Audio"
AdvSceneSwitcher.condition.audio.state.below="unter"
AdvSceneSwitcher.condition.audio.state.exact="genau"
AdvSceneSwitcher.condition.audio.state.above="über"
AdvSceneSwitcher.condition.audio.state.mute="stummgeschaltet"
AdvSceneSwitcher.condition.audio.state.unmute="nicht stummgeschaltet"
AdvSceneSwitcher.condition.audio.type.output="Ausgabe-Lautstärke"
AdvSceneSwitcher.condition.audio.type.volume="Konfigurierter Lautstärkepegel"
AdvSceneSwitcher.condition.audio.type.syncOffset="Sync-Offset"
AdvSceneSwitcher.condition.audio.type.monitor="Audio-Monitoring"
AdvSceneSwitcher.condition.audio.type.balance="Audio-Balance"
AdvSceneSwitcher.condition.audio.entry="{{checkType}} von {{audioSources}} ist {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.cursor="Cursor"
AdvSceneSwitcher.condition.cursor.type.region="ist in der Region"
AdvSceneSwitcher.condition.cursor.type.moving="bewegt sich"
AdvSceneSwitcher.condition.cursor.type.click="geklickt"
AdvSceneSwitcher.condition.cursor.button.left="Linke Maustaste"
AdvSceneSwitcher.condition.cursor.button.middle="Mittlere Maustaste"
AdvSceneSwitcher.condition.cursor.button.right="Rechte Maustaste"
AdvSceneSwitcher.condition.cursor.showFrame="Rahmen anzeigen"
AdvSceneSwitcher.condition.cursor.hideFrame="Rahmen ausblenden"
AdvSceneSwitcher.condition.cursor.entry.line1="Cursor {{conditions}}{{buttons}}{{minX}}{{minY}}{{maxX}}{{maxY}}{{toggleFrameButton}}"
AdvSceneSwitcher.condition.cursor.entry.line2="Cursor ist aktuell bei {{xPos}} x {{yPos}}"
AdvSceneSwitcher.condition.scene="Szene"
AdvSceneSwitcher.condition.scene.type.current="Aktuelle Szene ist"
AdvSceneSwitcher.condition.scene.type.previous="Vorherige Szene ist"
AdvSceneSwitcher.condition.scene.type.changed="Szene geändert"
AdvSceneSwitcher.condition.scene.type.notChanged="Szene hat sich nicht verändert"
AdvSceneSwitcher.condition.scene.type.currentPattern="Aktuelle Szene entspricht"
AdvSceneSwitcher.condition.scene.type.previousPattern="Vorherige Szene entspricht"
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Während des Übergangs die Ziel-Szene überprüfen"
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="Während des Übergangs die Quell-Szene überprüfen"
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}"
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Fenster"
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} existiert und ..."
AdvSceneSwitcher.condition.window.entry.line2="... ist {{fullscreen}} Vollbild {{maximized}} Maximiert {{focused}} Fokusiert {{windowFocusChanged}} Vordergrundfenster geändert"
AdvSceneSwitcher.condition.window.entry.line3="Aktuelles Vordergrundfenster: {{focusWindow}}"
AdvSceneSwitcher.condition.file="Datei"
AdvSceneSwitcher.condition.file.type.match="entspricht"
AdvSceneSwitcher.condition.file.type.contentChange="Inhalt geändert"
AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert"
AdvSceneSwitcher.condition.file.remote="Entfernte Datei"
AdvSceneSwitcher.condition.file.local="Lokale Datei"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
AdvSceneSwitcher.condition.media="Medien"
AdvSceneSwitcher.condition.media.source="Quelle"
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"
AdvSceneSwitcher.condition.media.allOnScene="Alle Medienquellen in"
AdvSceneSwitcher.condition.media.matchOnChange="Nur bei Änderung übereinstimmen (Hinweis: Diese Option wird in einer zukünftigen Version entfernt werden - bitte stattdessen Dauer-Modifikatoren verwenden)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="Leider verhalten sich nicht alle Medien-Quell-Typen gleich (z.B. Medien-Quelle vs. VLC-Video-Quelle \"Gestoppt\"-Status).\nBitte experimentieren, was in eurem Setup funktioniert!"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}Status ist{{states}}und{{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.video="Video"
AdvSceneSwitcher.condition.video.condition.match="entspricht genau"
AdvSceneSwitcher.condition.video.condition.differ="stimmt nicht überein"
AdvSceneSwitcher.condition.video.condition.hasChanged="hat sich geändert"
AdvSceneSwitcher.condition.video.condition.hasNotChanged="hat sich nicht verändert"
AdvSceneSwitcher.condition.video.condition.noImage="hat keine Ausgabe"
AdvSceneSwitcher.condition.video.condition.pattern="entspricht dem Muster"
AdvSceneSwitcher.condition.video.condition.object="enthält Objekt"
AdvSceneSwitcher.condition.video.condition.brightness="Helligkeit"
AdvSceneSwitcher.condition.video.askFileAction="Vorhandene Datei verwenden oder einen Screenshot der aktuell ausgewählten Quelle erstellen?"
AdvSceneSwitcher.condition.video.askFileAction.file="Vorhandene Datei verwenden"
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Screenshot erstellen"
AdvSceneSwitcher.condition.video.reduceLatency="Reduzierung der Abgleichslatenz"
AdvSceneSwitcher.condition.video.reduceLatency.tooltip="Durch die Aktivierung wird die Abgleichslatenz verringert, aber die Bedingungsprüfungen aller Makros werden insgesamt langsamer."
AdvSceneSwitcher.condition.video.usePatternForChangedCheck="Musterabgleich verwenden"
AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="So kann gesteuert werden, wie stark sich das Bild ändern muss, damit die Bedingung erfüllt ist."
AdvSceneSwitcher.condition.video.patternThreshold="Schwellenwert: "
AdvSceneSwitcher.condition.video.patternThresholdDescription="Ein höherer Schwellenwert bedeutet, dass das Muster stärker an die Videoquelle angepasst werden muss."
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="Alphakanal als Maske für Muster verwenden."
AdvSceneSwitcher.condition.video.brightnessThreshold="Durchschnittliche Helligkeit liegt über:"
AdvSceneSwitcher.condition.video.brightnessThresholdDescription="Ein hoher Wert steht für ein helles Bild, ein niedriger Wert für ein dunkles Bild."
AdvSceneSwitcher.condition.video.currentBrightness="Aktuelle durchschnittliche Helligkeit: %1"
AdvSceneSwitcher.condition.video.objectScaleThreshold="Skalierungsfaktor: "
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="Ein niedrigerer Skalierungsfaktor führt zu mehr Übereinstimmungen, aber zu einer höheren CPU-Belastung."
AdvSceneSwitcher.condition.video.minNeighborDescription="Ein höherer Wert für die Mindestanzahl von Nachbarn führt zu weniger, aber qualitativ besseren Übereinstimmungen."
AdvSceneSwitcher.condition.video.showMatch="Treffer anzeigen"
AdvSceneSwitcher.condition.video.showMatch.loading="Treffer werden gesucht"
AdvSceneSwitcher.condition.video.screenshotFail="Screenshot der Quelle konnte nicht erstellt werden!"
AdvSceneSwitcher.condition.video.screenshotEmpty="Screenshot ist leer - Ist die Quelle sichtbar?"
AdvSceneSwitcher.condition.video.patternMatchFail="Das Muster wurde nicht gefunden!"
AdvSceneSwitcher.condition.video.patternMatchSuccess="Das Muster ist rot hervorgehoben."
AdvSceneSwitcher.condition.video.objectMatchFail="Objekt wurde nicht gefunden!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="Objekt ist rot hervorgehoben."
AdvSceneSwitcher.condition.video.modelLoadFail="Modelldaten konnten nicht geladen werden!"
AdvSceneSwitcher.condition.video.type.main="OBS's Haupt-Ausgabe"
AdvSceneSwitcher.condition.video.type.source="Quelle"
AdvSceneSwitcher.condition.video.type.scene="Szene"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Kontrolle nur im Bereich durchführen"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.minSize="Minimale Größe:"
AdvSceneSwitcher.condition.video.maxSize="Maximale Größe:"
AdvSceneSwitcher.condition.video.selectArea="Bereich auswählen"
AdvSceneSwitcher.condition.video.selectArea.status="Nur der markierte Bereich wird überprüft"
AdvSceneSwitcher.condition.video.width="Breite"
AdvSceneSwitcher.condition.video.height="Höhe"
AdvSceneSwitcher.condition.stream="Stream"
AdvSceneSwitcher.condition.stream.state.start="Stream läuft"
AdvSceneSwitcher.condition.stream.state.stop="Stream gestoppt"
AdvSceneSwitcher.condition.stream.state.starting="Stream wird gestartet"
AdvSceneSwitcher.condition.stream.state.stopping="Stream wird gestoppt"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="Aufnahme"
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
AdvSceneSwitcher.condition.process="Prozess"
AdvSceneSwitcher.condition.process.entry="{{processes}} läuft {{focused}} und ist fokusiert"
AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
AdvSceneSwitcher.condition.idle="Leerlauf"
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
AdvSceneSwitcher.condition.pluginState="Plugin-Status"
AdvSceneSwitcher.condition.pluginState.state.start="Plugin gestartet"
AdvSceneSwitcher.condition.pluginState.state.restart="Plugin neu gestartet"
AdvSceneSwitcher.condition.pluginState.state.running="Plugin läuft"
AdvSceneSwitcher.condition.pluginState.state.shutdown="OBS wird runtergefahren"
AdvSceneSwitcher.condition.pluginState.state.sceneCollection="Szenensammlung geladen"
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Szene durch vorheriges Makro geändert"
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
AdvSceneSwitcher.condition.timer="Timer"
AdvSceneSwitcher.condition.timer.type.fixed="Fixe"
AdvSceneSwitcher.condition.timer.type.random="Zufällige"
AdvSceneSwitcher.condition.timer.pause="Pausieren"
AdvSceneSwitcher.condition.timer.continue="Fortfahren"
AdvSceneSwitcher.condition.timer.entry.line1.fixed="{{type}} Dauer von {{duration}} ist abgelaufen"
AdvSceneSwitcher.condition.timer.entry.line1.random="{{type}} Dauer von {{duration}} bis {{duration2}} ist abgelaufen"
AdvSceneSwitcher.condition.timer.entry.line2="Restliche Zeit: {{remaining}} Sekunden"
AdvSceneSwitcher.condition.timer.entry.line3="{{pauseContinue}} {{reset}} {{saveRemaining}} Verbleibende Zeit speichern {{autoReset}} Automatisches Zurücksetzen des Timers nach Erreichen der Dauer"
AdvSceneSwitcher.condition.timer.reset="Zurücksetzen"
AdvSceneSwitcher.condition.macro="Makro"
AdvSceneSwitcher.condition.macro.type.count="Zähler"
AdvSceneSwitcher.condition.macro.type.state="Zustand"
AdvSceneSwitcher.condition.macro.type.multiState="Mehrere Zustände"
AdvSceneSwitcher.condition.macro.type.selection="Bedingungs-Typ: {{types}}"
AdvSceneSwitcher.condition.macro.count.type.below="Weniger als"
AdvSceneSwitcher.condition.macro.count.type.above="Mehr als"
AdvSceneSwitcher.condition.macro.count.type.equal="Exakt"
AdvSceneSwitcher.condition.macro.state.type.below="Weniger als"
AdvSceneSwitcher.condition.macro.state.type.above="Mehr als"
AdvSceneSwitcher.condition.macro.state.type.equal="Exakt"
AdvSceneSwitcher.condition.macro.count.reset="Zurücksetzen"
AdvSceneSwitcher.condition.macro.pausedWarning="Ausgewähltes Makro ist derzeit pausiert!"
AdvSceneSwitcher.condition.macro.state.entry="Bedingungen für {{macros}} sind wahr"
AdvSceneSwitcher.condition.macro.multistate.entry="Bedingungen für {{multiStateConditions}}{{multiStateCount}} der folgenden Makros wahr sind:"
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} wurde ausgeführt {{conditions}} {{count}} Mal"
AdvSceneSwitcher.condition.macro.count.entry.line2="Aktuelle Anzahl: {{currentCount}} {{resetCount}}"
AdvSceneSwitcher.condition.source="Quelle"
AdvSceneSwitcher.condition.source.type.active="Ist aktiv"
AdvSceneSwitcher.condition.source.type.showing="Wird angezeigt"
AdvSceneSwitcher.condition.source.type.settings="Einstellungen stimmen überein"
AdvSceneSwitcher.condition.source.getSettings="Aktuelle Einstellungen abfragen"
AdvSceneSwitcher.condition.source.entry.line1="{{sources}} {{conditions}}"
AdvSceneSwitcher.condition.source.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.source.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.virtualCamera="Virtuelle Kamera"
AdvSceneSwitcher.condition.virtualCamera.state.start="Virtuelle Kamera gestartet"
AdvSceneSwitcher.condition.virtualCamera.state.stop="Virtuelle Kamera gestoppt"
AdvSceneSwitcher.condition.virtualCamera.entry="{{states}}"
AdvSceneSwitcher.condition.filter="Filter"
AdvSceneSwitcher.condition.filter.type.active="Ist aktiviert"
AdvSceneSwitcher.condition.filter.type.showing="Ist deaktiviert"
AdvSceneSwitcher.condition.filter.type.settings="Einstellungen passen"
AdvSceneSwitcher.condition.filter.getSettings="Aktuelle Einstellungen abrufen"
AdvSceneSwitcher.condition.filter.entry.line1="Auf {{sources}} {{filters}} {{conditions}}"
AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.filter.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.sceneOrder="Reihenfolge der Szenenelemente"
AdvSceneSwitcher.condition.sceneOrder.type.above="Ist über"
AdvSceneSwitcher.condition.sceneOrder.type.below="Ist unter"
AdvSceneSwitcher.condition.sceneOrder.type.position="Ist in Position"
AdvSceneSwitcher.condition.sceneOrder.positionInfo="Der Positionswert beginnt ganz unten bei 0 und erhöht sich für jedes Szenenelement, auch in Szenengruppen, um eins"
AdvSceneSwitcher.condition.sceneOrder.entry="Auf{{scenes}}{{sources}}{{conditions}}{{sources2}}{{position}}"
AdvSceneSwitcher.condition.hotkey="Hotkey"
AdvSceneSwitcher.condition.hotkey.name="Makro-Trigger-Hotkey"
AdvSceneSwitcher.condition.hotkey.tip="Hinweis: Die Tastenkombinationen für diesen Hotkey können in den OBS-Einstellungen konfiguriert werden"
AdvSceneSwitcher.condition.hotkey.entry.line1="Hotkey ist gedrückt"
AdvSceneSwitcher.condition.hotkey.entry.line2="Name: {{name}}"
AdvSceneSwitcher.condition.replay="Replay Buffer"
AdvSceneSwitcher.condition.replay.state.stopped="Replay Buffer gestoppt"
AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert"
AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="Datum"
AdvSceneSwitcher.condition.date.anyDay="Beliebiger Tag"
AdvSceneSwitcher.condition.date.monday="Montag"
AdvSceneSwitcher.condition.date.tuesday="Dienstag"
AdvSceneSwitcher.condition.date.wednesday="Mittwoch"
AdvSceneSwitcher.condition.date.thursday="Donnerstag"
AdvSceneSwitcher.condition.date.friday="Freitag"
AdvSceneSwitcher.condition.date.saturday="Samstag"
AdvSceneSwitcher.condition.date.sunday="Sonntag"
AdvSceneSwitcher.condition.date.state.at="Am"
AdvSceneSwitcher.condition.date.state.after="Nach"
AdvSceneSwitcher.condition.date.state.before="Vor"
AdvSceneSwitcher.condition.date.state.between="Zwischen"
AdvSceneSwitcher.condition.date.state.pattern="Muster"
AdvSceneSwitcher.condition.date.separator="und"
AdvSceneSwitcher.condition.date.ignoreDate="Wenn diese Option nicht aktiviert ist, wird die Datumskomponente ignoriert"
AdvSceneSwitcher.condition.date.ignoreTime="Wenn diese Option nicht aktiviert ist, wird die Zeitkomponente ignoriert"
AdvSceneSwitcher.condition.date.showAdvancedSettings="Erweiterte Einstellungen anzeigen"
AdvSceneSwitcher.condition.date.showSimpleSettings="Einfache Einstellungen anzeigen"
AdvSceneSwitcher.condition.date.entry.simple="Am {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
AdvSceneSwitcher.condition.date.entry.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Nächster Treffer bei: %1"
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten"
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Auf{{scenes}}{{sources}}passt zur Transformation"
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.transition="Übergang"
AdvSceneSwitcher.condition.transition.type.current="Aktueller Übergangstyp ist"
AdvSceneSwitcher.condition.transition.type.duration="Aktuelle Übergangsdauer beträgt"
AdvSceneSwitcher.condition.transition.type.started="Übergang gestartet"
AdvSceneSwitcher.condition.transition.type.ended="Übergang beendet"
AdvSceneSwitcher.condition.transition.type.transitionSource="Übergang von"
AdvSceneSwitcher.condition.transition.type.transitionTarget="Übergang zu"
AdvSceneSwitcher.condition.transition.durationSuffix="Sekunden"
AdvSceneSwitcher.condition.transition.entry="{{conditions}}{{transitions}}{{scenes}}{{duration}}{{durationSuffix}}"
AdvSceneSwitcher.condition.sceneVisibility="Sichtbarkeit von Szenenelementen"
AdvSceneSwitcher.condition.sceneVisibility.type.shown="ist sichtbar"
AdvSceneSwitcher.condition.sceneVisibility.type.hidden="ist versteckt"
AdvSceneSwitcher.condition.sceneVisibility.type.changed="Sichtbarkeit verändert"
AdvSceneSwitcher.condition.sceneVisibility.entry="Auf{{scenes}}{{sources}}{{conditions}}"
AdvSceneSwitcher.condition.studioMode="Studio-Modus"
AdvSceneSwitcher.condition.studioMode.state.active="Studio-Modus ist aktiviert"
AdvSceneSwitcher.condition.studioMode.state.notActive="Studio-Modus ist nicht aktiviert"
AdvSceneSwitcher.condition.studioMode.state.previewScene="Vorschau-Szene ist"
AdvSceneSwitcher.condition.studioMode.entry="{{conditions}}{{scenes}}"
AdvSceneSwitcher.condition.openvr="OpenVR"
AdvSceneSwitcher.condition.openvr.errorStatus="OpenVR Fehler: "
AdvSceneSwitcher.condition.openvr.entry.line1="HMD ist in ..."
AdvSceneSwitcher.condition.openvr.entry.line2="{{controls}}"
AdvSceneSwitcher.condition.openvr.entry.line3="HMD ist derzeit bei {{xPos}} x {{yPos}} x {{zPos}}"
AdvSceneSwitcher.condition.stats="OBS-Statistiken"
AdvSceneSwitcher.condition.stats.type.fps="FPS"
AdvSceneSwitcher.condition.stats.type.CPUUsage="CPU-Auslastung"
AdvSceneSwitcher.condition.stats.type.HDDSpaceAvailable="Verfügbarer Speicherplatz"
AdvSceneSwitcher.condition.stats.type.memoryUsage="Speicherverbrauch"
AdvSceneSwitcher.condition.stats.type.averageTimeToRender="Durchschnittliche Zeit zum Rendern eines Frames"
AdvSceneSwitcher.condition.stats.type.skippedFrames="Übersprungene Frames aufgrund der Kodierungsverzögerung"
AdvSceneSwitcher.condition.stats.type.missedFrames="Verpasste Frames durch Rendering-Verzögerung"
AdvSceneSwitcher.condition.stats.type.droppedFrames.stream="Verlorene Frames im Stream"
AdvSceneSwitcher.condition.stats.type.megabytesSent.stream="Gesamtdatenmenge des Streams"
AdvSceneSwitcher.condition.stats.type.bitrate.stream="Stream-Bitrate"
AdvSceneSwitcher.condition.stats.type.droppedFrames.recording="Verlorene Frames bei der Aufnahme"
AdvSceneSwitcher.condition.stats.type.megabytesSent.recording="Gesamtdatenmenge der Aufnahme"
AdvSceneSwitcher.condition.stats.type.bitrate.recording="Aufnahme-Bitrate"
AdvSceneSwitcher.condition.stats.condition.above="über"
AdvSceneSwitcher.condition.stats.condition.equals="gleich"
AdvSceneSwitcher.condition.stats.condition.below="unter"
AdvSceneSwitcher.condition.stats.dockHint="Das Dock \"Stats\" öffnen, um den aktuellen Status anzuzeigen"
AdvSceneSwitcher.condition.stats.entry="{{stats}} ist {{condition}} {{value}}"
AdvSceneSwitcher.condition.profile="Profil"
AdvSceneSwitcher.condition.profile.entry="Derzeit aktives Profil ist {{profiles}}"
AdvSceneSwitcher.condition.websocket="Websocket"
AdvSceneSwitcher.condition.websocket.type.request="Anfrage"
AdvSceneSwitcher.condition.websocket.type.event="Ereignis"
AdvSceneSwitcher.condition.websocket.useRegex="Reguläre Ausdrücke verwenden"
AdvSceneSwitcher.condition.websocket.entry.request="{{type}} wurde empfangen:"
AdvSceneSwitcher.condition.websocket.entry.event="{{type}} wurde empfangen von {{connection}}:"
AdvSceneSwitcher.condition.variable="Variabel"
AdvSceneSwitcher.condition.variable.type.compare="entspricht"
AdvSceneSwitcher.condition.variable.type.empty="ist leer"
AdvSceneSwitcher.condition.variable.type.number="ist eine Zahl"
AdvSceneSwitcher.condition.variable.type.lessThan="ist kleiner als"
AdvSceneSwitcher.condition.variable.type.greaterThan="ist größer als"
AdvSceneSwitcher.condition.variable.type.valueChanged="Wert verändert"
AdvSceneSwitcher.condition.variable.type.equalsVariable="entspricht Variable"
AdvSceneSwitcher.condition.variable.type.lessThanVariable="ist kleiner als die Variable"
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als die Variable"
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
; Macro Actions
AdvSceneSwitcher.action.switchScene="Szene wechseln"
AdvSceneSwitcher.action.scene.entry="Wechsle zu Szene{{scenes}}mittels{{transitions}}mit einer Dauer von{{duration}}Sekunden"
AdvSceneSwitcher.action.scene.entry.noDuration="Wechsle zu Szene{{scenes}}mittels{{transitions}}"
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Warten, bis der Übergang zur Zielszene abgeschlossen ist"
AdvSceneSwitcher.action.wait="Warten"
AdvSceneSwitcher.action.wait.type.fixed="fixe"
AdvSceneSwitcher.action.wait.type.random="zufällig"
AdvSceneSwitcher.action.wait.entry.fixed="Warte für {{waitType}} Dauer von {{duration}}"
AdvSceneSwitcher.action.wait.entry.random="Warte für {{waitType}} Dauer von {{duration}} bis {{duration2}}"
AdvSceneSwitcher.action.audio="Audio"
AdvSceneSwitcher.action.audio.type.mute="Stummgeschaltet"
AdvSceneSwitcher.action.audio.type.unmute="Nicht stummgeschaltet"
AdvSceneSwitcher.action.audio.type.sourceVolume="Quell-Lautstärke einstellen"
AdvSceneSwitcher.action.audio.type.masterVolume="Master-Lautstärke einstellen"
AdvSceneSwitcher.action.audio.type.syncOffset="Sync-Offset einstellen"
AdvSceneSwitcher.action.audio.type.monitor="Audio-Monitoring einstellen"
AdvSceneSwitcher.action.audio.type.balance="Audio-Balance einstellen"
AdvSceneSwitcher.action.audio.balance.description="Den Schieberegler in die Richtung des Audiokanals drehen, auf den fokussiert werden soll."
AdvSceneSwitcher.action.audio.fade.type.duration="über eine Dauer von"
AdvSceneSwitcher.action.audio.fade.type.rate="mit einer Rate von"
AdvSceneSwitcher.action.audio.fade.duration="{{fade}}Blende {{fadeTypes}} {{duration}} Sekunden."
AdvSceneSwitcher.action.audio.fade.rate="{{fade}}Blende {{fadeTypes}} {{rate}}pro Sekunde."
AdvSceneSwitcher.action.audio.fade.wait="Warten, bis die Blende abgeschlossen ist."
AdvSceneSwitcher.action.audio.fade.abort="Abbruch einer bereits aktiven Blende."
AdvSceneSwitcher.action.audio.entry="{{actions}}{{audioSources}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.action.recording="Aufnahme"
AdvSceneSwitcher.action.recording.type.stop="Aufnahme stoppen"
AdvSceneSwitcher.action.recording.type.start="Aufnahme starten"
AdvSceneSwitcher.action.recording.type.pause="Aufnahme pausieren"
AdvSceneSwitcher.action.recording.type.unpause="Aufnahme nicht mehr pausieren"
AdvSceneSwitcher.action.recording.type.split="Aufnahme-Datei teilen"
AdvSceneSwitcher.action.recording.pause.hint="Bitte beachten, dass je nach Aufnahmeeinstellung die Aufnahme möglicherweise nicht unterbrochen werden kann"
AdvSceneSwitcher.action.recording.split.hint="Vergewissern, dass die automatische Dateiaufteilung in den OBS-Einstellungen aktiviert ist!"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Replay Buffer"
AdvSceneSwitcher.action.replay.saveWarn="Warnung: Ein zu häufiges Speichern kann dazu führen, dass der Replay Buffer nicht gespeichert wird!"
AdvSceneSwitcher.action.replay.type.stop="Replay Buffer stoppen"
AdvSceneSwitcher.action.replay.type.start="Replay Buffer starten"
AdvSceneSwitcher.action.replay.type.save="Replay Buffer speichern"
AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Stream"
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Ausführen"
AdvSceneSwitcher.action.run.arguments="Argumente:"
AdvSceneSwitcher.action.run.addArgument="Argument hinzufügen"
AdvSceneSwitcher.action.run.addArgumentDescription="Neues Argument hinzufügen:"
AdvSceneSwitcher.action.run.entry="Ausführen {{filePath}}"
AdvSceneSwitcher.action.run.entry.workingDirectory="Arbeitsverzeichnis:{{workingDirectory}}"
AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen"
AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig"
AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.filter="Filter"
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
AdvSceneSwitcher.action.filter.type.settings="Einstellungen festlegen"
AdvSceneSwitcher.action.filter.entry="Auf {{sources}} {{actions}} {{filters}}"
AdvSceneSwitcher.action.filter.getSettings="Aktuelle Einstellungen abfragen"
AdvSceneSwitcher.action.source="Quelle"
AdvSceneSwitcher.action.source.type.enable="Aktivieren"
AdvSceneSwitcher.action.source.type.disable="Deaktivieren"
AdvSceneSwitcher.action.source.type.settings="Einstellungen festlegen"
AdvSceneSwitcher.action.source.type.refreshSettings="Aktualisieren der Quelleneinstellungen"
AdvSceneSwitcher.action.source.type.pressSettingsButton="Drücken der Einstellungstaste"
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Kann verwendet werden, um Browser-, Medien- usw. Quellen zu aktualisieren"
AdvSceneSwitcher.action.source.noSettingsButtons="Keine Buttons gefunden!"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
AdvSceneSwitcher.action.source.warning="Warnung: Das globale Aktivieren und Deaktivieren von Quellen kann nicht über die OBS-Benutzeroberfläche gesteuert werden"
AdvSceneSwitcher.action.source.getSettings="Aktuelle Einstellungen abfragen"
AdvSceneSwitcher.action.media="Medien"
AdvSceneSwitcher.action.media.type.play="Abspielen"
AdvSceneSwitcher.action.media.type.pause="Pausieren"
AdvSceneSwitcher.action.media.type.stop="Stoppen"
AdvSceneSwitcher.action.media.type.restart="Neu starten"
AdvSceneSwitcher.action.media.type.next="Nächste"
AdvSceneSwitcher.action.media.type.previous="Vorherige"
AdvSceneSwitcher.action.media.type.seek="Suche nach"
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
AdvSceneSwitcher.action.macro="Makro"
AdvSceneSwitcher.action.macro.type.pause="Pausieren"
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Plugin-Status"
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
AdvSceneSwitcher.action.pluginState.type.import="Einstellungen importieren aus"
AdvSceneSwitcher.action.pluginState.importWarning="Hinweis: Die Aktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Virtuelle Kamera"
AdvSceneSwitcher.action.virtualCamera.type.stop="Virtuelle Kamera stoppen"
AdvSceneSwitcher.action.virtualCamera.type.start="Virtuelle Kamera starten"
AdvSceneSwitcher.action.virtualCamera.entry="{{actions}}"
AdvSceneSwitcher.action.hotkey="Hotkey"
AdvSceneSwitcher.action.hotkey.leftShift="Linke Umschalttaste"
AdvSceneSwitcher.action.hotkey.rightShift="Rechte Umschalttaste"
AdvSceneSwitcher.action.hotkey.leftCtrl="Linke Strg-Taste"
AdvSceneSwitcher.action.hotkey.rightCtrl="Rechte Strg-Taste"
AdvSceneSwitcher.action.hotkey.leftAlt="Linke Alt-Taste"
AdvSceneSwitcher.action.hotkey.rightAlt="Rechte Alt-Taste"
AdvSceneSwitcher.action.hotkey.leftMeta="Linke Meta-Taste"
AdvSceneSwitcher.action.hotkey.rightMeta="Rechte Meta-Taste"
AdvSceneSwitcher.action.hotkey.onlyOBS="Tastendruck nur an OBS senden"
AdvSceneSwitcher.action.hotkey.disabled="Globale Tastendrücke können nicht simuliert werden - die Funktionalität beschränkt sich auf das Senden von Tastendrücken an OBS!"
AdvSceneSwitcher.action.hotkey.entry="Drücke {{keys}} für {{duration}} Millisekunden"
AdvSceneSwitcher.action.sceneOrder="Reihenfolge der Szenenelemente"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Nach oben verschieben"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Nach unten verschieben"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="An erste Stelle verschieben"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="An letzte Stelle verschieben"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="An Position verschieben"
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Szenenelement transformieren"
AdvSceneSwitcher.action.sceneTransform.getTransform="Transformation erhalten"
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}transformieren{{sources}}"
AdvSceneSwitcher.action.file="Datei"
AdvSceneSwitcher.action.file.type.write="Schreiben"
AdvSceneSwitcher.action.file.type.append="Anhängen"
AdvSceneSwitcher.action.file.entry="{{actions}} in {{filePath}}:"
AdvSceneSwitcher.action.studioMode="Studio-Modus"
AdvSceneSwitcher.action.studioMode.type.swap="Vorschau- und Programm-Szene tauschen"
AdvSceneSwitcher.action.studioMode.type.setScene="Vorschau-Szene einstellen auf"
AdvSceneSwitcher.action.studioMode.type.enable="Studio-Modus aktivieren"
AdvSceneSwitcher.action.studioMode.type.disable="Studio-Modus deaktivieren"
AdvSceneSwitcher.action.studioMode.entry="{{actions}}{{scenes}}"
AdvSceneSwitcher.action.transition="Übergang"
AdvSceneSwitcher.action.transition.type.scene="Szenenübergang"
AdvSceneSwitcher.action.transition.type.sceneOverride="Szenenübergang überschreiben"
AdvSceneSwitcher.action.transition.type.sourceShow="Übergang der Quelle anzeigen"
AdvSceneSwitcher.action.transition.type.sourceHide="Übergang der Quelle verstecken"
AdvSceneSwitcher.action.transition.entry.line1="Anpassen {{type}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Übergangstyp festlegen auf {{transitions}}"
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Übergangsdauer festlegen auf {{duration}}Sekunden"
AdvSceneSwitcher.action.timer="Timer"
AdvSceneSwitcher.action.timer.type.pause="Pausieren"
AdvSceneSwitcher.action.timer.type.continue="Fortsetzen"
AdvSceneSwitcher.action.timer.type.reset="Zurücksetzen"
AdvSceneSwitcher.action.timer.type.setTimeRemaining="Verbleibende Zeit einstellen der"
AdvSceneSwitcher.action.timer.entry="{{timerAction}} Timer von {{macros}} {{duration}}"
AdvSceneSwitcher.action.random="Zufall"
AdvSceneSwitcher.action.random.allowRepeat="Aufeinanderfolgende Ausführung desselben Makros zulassen"
AdvSceneSwitcher.action.random.entry="Zufällige Ausführung eines der folgenden Makros (pausierte Makros werden ignoriert)"
AdvSceneSwitcher.action.systray="Benachrichtigung im System-Tray"
AdvSceneSwitcher.action.systray.entry="Benachrichtigung anzeigen: {{message}}"
AdvSceneSwitcher.action.screenshot="Screenshot"
AdvSceneSwitcher.action.screenshot.save.default="Standard"
AdvSceneSwitcher.action.screenshot.save.custom="Benutzerdefiniert"
AdvSceneSwitcher.action.screenshot.type.source="Quelle"
AdvSceneSwitcher.action.screenshot.type.scene="Szene"
AdvSceneSwitcher.action.screenshot.mainOutput="OBS's Haupt-Ausgabe"
AdvSceneSwitcher.action.screenshot.blackscreenNote="Quellen oder Szenen, die nicht immer gerendert werden, können dazu führen, dass einige Teile der Screenshots leer bleiben."
AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}und speichere in{{saveType}}Pfad"
AdvSceneSwitcher.action.profile="Profil"
AdvSceneSwitcher.action.profile.entry="Aktives Profil umschalten auf {{profiles}}"
AdvSceneSwitcher.action.sceneCollection="Szenensammlung"
AdvSceneSwitcher.action.sceneCollection.entry="Aktive Szenensammlung umschalten auf {{sceneCollections}}"
AdvSceneSwitcher.action.sceneCollection.warning="Hinweis: Alle danach folgenden Aktionen werden nicht ausgeführt, da durch die Änderung der Szenensammlung auch die Einstellungen des Szenenwechslers neu geladen werden.\nDie Szenensammlungsaktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
AdvSceneSwitcher.action.sequence="Sequenz"
AdvSceneSwitcher.action.sequence.entry="Jedes Mal, wenn diese Aktion ausgeführt wird, wird das nächste Makro in der Liste ausgeführt (pausierte Makros werden ignoriert)"
AdvSceneSwitcher.action.sequence.status="Zuletzt ausgeführtes Makro: %1 - Nächstes auszuführendes Makro: %2"
AdvSceneSwitcher.action.sequence.status.none="keines"
AdvSceneSwitcher.action.sequence.restart="Neustart am Anfang, wenn das Ende der Liste erreicht ist"
AdvSceneSwitcher.action.sequence.continueFrom="Weiter mit ausgewähltem Element"
AdvSceneSwitcher.action.websocket="Websocket"
AdvSceneSwitcher.action.websocket.type.request="Anfrage"
AdvSceneSwitcher.action.websocket.type.event="Ereignis"
AdvSceneSwitcher.action.websocket.entry.request="Szenenwechsler {{type}} via {{connection}} senden"
AdvSceneSwitcher.action.websocket.entry.event="Szenenwechsler {{type}} an verbundene Clients senden"
AdvSceneSwitcher.action.http="HTTP"
AdvSceneSwitcher.action.http.type.get="GET"
AdvSceneSwitcher.action.http.type.post="POST"
AdvSceneSwitcher.action.http.entry.line1="Sende {{method}} an {{url}}"
AdvSceneSwitcher.action.http.entry.line2="Timeout: {{timeout}} Sekunden"
AdvSceneSwitcher.action.variable="Variabel"
AdvSceneSwitcher.action.variable.type.set="Auf festen Wert einstellen"
AdvSceneSwitcher.action.variable.type.append="Anhängen"
AdvSceneSwitcher.action.variable.type.appendVar="Variable anhängen"
AdvSceneSwitcher.action.variable.type.increment="Erhöhen"
AdvSceneSwitcher.action.variable.type.decrement="Verringern"
AdvSceneSwitcher.action.variable.type.setActionValue="Auf Aktionswert setzen"
AdvSceneSwitcher.action.variable.type.setConditionValue="Auf Bedingungswert setzen"
AdvSceneSwitcher.action.variable.invalidSelection="Ungültige Auswahl!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Aktionen wird nicht unterstützt!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Szenenübergänge"
AdvSceneSwitcher.transitionTab.transitionForAToB="Szenenübergänge für automatisierte Szenenwechsel von Szene A zu Szene B"
@@ -117,6 +651,7 @@ AdvSceneSwitcher.mediaTab.states.Paused="Pausiert"
AdvSceneSwitcher.mediaTab.states.stopped="Gestoppt"
AdvSceneSwitcher.mediaTab.states.ended="Beendet"
AdvSceneSwitcher.mediaTab.states.error="Fehler"
AdvSceneSwitcher.mediaTab.states.playlistEnd="Ended(Playlist)"
AdvSceneSwitcher.mediaTab.states.any="Beliebig"
AdvSceneSwitcher.mediaTab.timeRestriction.none="Keine Auswahl"
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="Dauer kürzer"
@@ -190,10 +725,10 @@ AdvSceneSwitcher.sceneSequenceTab.loadFail="Laden der Einstellungen ist fehlgesc
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Laden der Einstellungen war erfolgreich!"
AdvSceneSwitcher.sceneSequenceTab.fileType="Text Dateien (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.interruptible="kann unterbrochen werden"
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} mit {{transitions}} {{interruptible}}"
AdvSceneSwitcher.sceneSequenceTab.extendEdit="Szenenfolge erweitern"
AdvSceneSwitcher.sceneSequenceTab.extendEntry="Nach {{delay}} wechsle zu {{scenes}} mit {{transitions}}"
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} mit {{transitions}} {{interruptible}}"
AdvSceneSwitcher.sceneSequenceTab.help="Dieser Tab ermöglicht es automatisiert zu einer anderen Szene zu wechseln, nachdem eine Szene für die konfigurierte Zeit aktiv war.\nZum Beispiel kann so automatisch zwischen zwei Szenen hin und her gewechselt werden.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
; Audio Tab
@@ -221,6 +756,7 @@ AdvSceneSwitcher.videoTab.help="<html><head/><body><p>Dieser Tab ermöglicht es
; Network Tab
AdvSceneSwitcher.networkTab.title="Netzwerk"
AdvSceneSwitcher.networkTab.description="Über diesen Tab kann die aktive Szene einer anderen OBS-Instanz ferngesteuert werden.\nBitte beachten, dass die Szenennamen auf allen OBS-Instanzen exakt übereinstimmen müssen."
AdvSceneSwitcher.networkTab.warning="Die Verwendung des Servers außerhalb eines lokalen Netzwerks kann dazu führen, dass die aktive Szene von dritten Personen ausgelesen werden kann."
AdvSceneSwitcher.networkTab.server="Server starten (Sendet Szenenwechselnachrichten zu allen verbundenen Clients)"
AdvSceneSwitcher.networkTab.server.port="Port"
@@ -287,35 +823,111 @@ AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopVirtualCamera="Virtuelle
AdvSceneSwitcher.sceneTriggerTab.entry="Wenn {{scenes}} {{triggers}} {{actions}} {{audioSources}} nach {{duration}} "
AdvSceneSwitcher.sceneTriggerTab.help="Dieser Tab ermöglicht es automatisiert Handlungen, wie etwa das Stoppen von einer Aufnahme oder des Streamens, bei einem Szenenwechsel auszuführen."
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Starte den Erweiteren Szenenwechsler"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stoppe den Erweiteren Szenenwechsler"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweiteren Szenenwechsler"
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Starte den Erweiterten Szenenwechsler"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stoppe den Erweiterten Szenenwechsler"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweiterten Szenenwechsler"
AdvSceneSwitcher.hotkey.macro.pause="Pausiere Makro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Makro %1 nicht mehr pausieren"
AdvSceneSwitcher.hotkey.macro.togglePause="Pause von Makro %1 togglen"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Makro-Segmentauswahl nach oben verschieben"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Makro-Segmentauswahl nach unten verschieben"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Ausgewähltes Makro-Segment entfernen"
AdvSceneSwitcher.askBackup="Neue Version des Erweiterten Automatischen Szenenwechslers wurde erkannt.\nSoll ein Backup der alten Einstellungen angelegt werden?"
AdvSceneSwitcher.askForMacro="Makro auswählen {{macroSelection}}"
AdvSceneSwitcher.close="Schließen"
AdvSceneSwitcher.browse="Öffnen"
AdvSceneSwitcher.item.select="--Element auswählen--"
AdvSceneSwitcher.item.add="Neues Element hinzufügen"
AdvSceneSwitcher.item.rename="Umbenennen"
AdvSceneSwitcher.item.remove="Entfernen"
AdvSceneSwitcher.item.properties="Einstellungen"
AdvSceneSwitcher.item.newName="Neuer Name:"
AdvSceneSwitcher.item.emptyName="Leerer Name nicht zulässig!"
AdvSceneSwitcher.item.nameNotAvailable="Name nicht verfügbar!"
AdvSceneSwitcher.item.nameReserved="Name reserviert!"
AdvSceneSwitcher.variable.select="--Variable auswählen--"
AdvSceneSwitcher.variable.add="Neue Variable hinzufügen"
AdvSceneSwitcher.variable.name="Name:"
AdvSceneSwitcher.variable.value="Aktueller Wert:"
AdvSceneSwitcher.variable.save="Verhalten speichern / laden"
AdvSceneSwitcher.variable.save.dontSave="Variablenwert nicht speichern"
AdvSceneSwitcher.variable.save.save="Variablenwert speichern"
AdvSceneSwitcher.variable.save.default="Auf Wert setzen"
AdvSceneSwitcher.connection.select="--Verbindung auswählen--"
AdvSceneSwitcher.connection.add="Neue Verbindung hinzufügen"
AdvSceneSwitcher.connection.name="Name:"
AdvSceneSwitcher.connection.address="Adresse:"
AdvSceneSwitcher.connection.port="Port:"
AdvSceneSwitcher.connection.password="Passwort:"
AdvSceneSwitcher.connection.reconnect="Automatisch neu verbinden:"
AdvSceneSwitcher.connection.reconnectDelay="Automatisch neu verbinden nach:"
AdvSceneSwitcher.connection.connectOnStart="Beim Start verbinden:"
AdvSceneSwitcher.connection.test="Verbindung testen"
AdvSceneSwitcher.connection.status.disconnected="Verbindung getrennt"
AdvSceneSwitcher.connection.status.connecting="Verbindung wird aufgebaut"
AdvSceneSwitcher.connection.status.connected="Verbunden, aber nicht authentifiziert"
AdvSceneSwitcher.connection.status.authenticated="Verbunden und authentifiziert"
AdvSceneSwitcher.regex.enable="Reguläre Ausdrücke aktivieren"
AdvSceneSwitcher.regex.partialMatch="Teilweise Übereinstimmung zulassen"
AdvSceneSwitcher.regex.caseInsensitive="Groß- und Kleinschreibung wird nicht berücksichtigt"
AdvSceneSwitcher.regex.dotMatchNewline=". erkennt Zeilenumbrüche"
AdvSceneSwitcher.regex.multiLine="^ und $ erkennen Start/Ende einer Zeile"
AdvSceneSwitcher.regex.extendedPattern="Qt's ExtendedPatternSyntax aktivieren"
AdvSceneSwitcher.selectScene="--Szene auswählen--"
AdvSceneSwitcher.selectPreviousScene="Vorhergehende Szene"
AdvSceneSwitcher.currentTransition="Aktueller Szenenübergang"
AdvSceneSwitcher.selectTransition="--Szenenübergang auswählen--"
AdvSceneSwitcher.selectPreviousScene="Vorherige Szene"
AdvSceneSwitcher.selectCurrentScene="Aktuelle Szene"
AdvSceneSwitcher.selectPreviewScene="Vorschau-Szene"
AdvSceneSwitcher.selectAnyScene="Beliebige Szene"
AdvSceneSwitcher.currentTransition="Aktueller Übergang"
AdvSceneSwitcher.anyTransition="Beliebiger Übergang"
AdvSceneSwitcher.selectTransition="--Übergang auswählen--"
AdvSceneSwitcher.selectWindow="--Fenster auswählen--"
AdvSceneSwitcher.selectAudioSource="--Audio Quelle auswählen--"
AdvSceneSwitcher.selectVideoSource="--Video Quelle auswählen--"
AdvSceneSwitcher.selectMediaSource="--Medien Quelle auswählen--"
AdvSceneSwitcher.selectSource="--Quelle auswählen--"
AdvSceneSwitcher.selectAudioSource="--Audio-Quelle auswählen--"
AdvSceneSwitcher.selectVideoSource="--Video-Quelle auswählen--"
AdvSceneSwitcher.OBSVideoOutput="OBS's Haupt-Ausgabe"
AdvSceneSwitcher.selectMediaSource="--Medien-Quelle auswählen--"
AdvSceneSwitcher.selectProcess="--Prozess auswählen--"
AdvSceneSwitcher.selectFilter="--Filter auswählen--"
AdvSceneSwitcher.selectMacro="--Makro auswählen--"
AdvSceneSwitcher.selectItem="--Element auswählen--"
AdvSceneSwitcher.selectProfile="--Profil auswählen--"
AdvSceneSwitcher.selectSceneCollection="--Szenensammlung auswählen--"
AdvSceneSwitcher.enterPath="--Pfad eingeben--"
AdvSceneSwitcher.enterText="--Text eingeben--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="Ungültige Einträge werden nicht gespeichert"
AdvSceneSwitcher.selectWindowTip="Benutze \"OBS\" um das OBS-Studio Fenster auszuwählen\nBenutze\"Task Switching\"um die ALT + TAB Tastenkombination auszuwählen"
AdvSceneSwitcher.enterURL="--URL eingebenL--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="ungültige Einträge werden nicht gespeichert"
AdvSceneSwitcher.selectWindowTip="Verwende \"OBS\", um das OBS-Fenster zu definieren.\n Verwende \"Task Switching\", um ALT + TAB festzulegen."
AdvSceneSwitcher.sceneItemSelection.all="Alle"
AdvSceneSwitcher.sceneItemSelection.any="Beliebige"
AdvSceneSwitcher.status.active="Aktiv"
AdvSceneSwitcher.status.inactive="Inaktiv"
AdvSceneSwitcher.running="Plugin läuft"
AdvSceneSwitcher.stopped="Plugin gestoppt"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>Dies scheint das erste Mal zu sein, dass der Erweiterte Szenenwechsler gestartet wurde.<br>Bitte schaue ins <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> für eine Liste von Anleitungen und Beispielen.<br>Nicht zögern und Fragen im <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">Thread</span></a> des Plugins im OBS-Forum stellen!!</p></body></html>"
AdvSceneSwitcher.deprecatedTabWarning="Die Entwicklung für dieses Tab wurde gestoppt!\nBitte stattdessen zur Verwendung des Makros-Tab übergehen.\nDieser Hinweis kann im Allgemein-Tab deaktiviert werden."
AdvSceneSwitcher.unit.milliseconds="Millisekunden"
AdvSceneSwitcher.unit.secends="Sekunden"
AdvSceneSwitcher.unit.minutes="Minuten"
AdvSceneSwitcher.unit.hours="Stunden"
AdvSceneSwitcher.duration.condition.none="Kein Dauer-Modifikator"
AdvSceneSwitcher.duration.condition.more="Mindestens für"
AdvSceneSwitcher.duration.condition.equal="Für genau"
AdvSceneSwitcher.duration.condition.less="Höchstens für"
AdvSceneSwitcher.duration.condition.within="In den letzten"
AdvSceneSwitcher.audio.monitor.none="Monitoring aus"
AdvSceneSwitcher.audio.monitor.monitorOnly="Nur Monitoring (Ausgabe stummschalten)"
AdvSceneSwitcher.audio.monitor.both="Monitoring und Ausgabe"

View File

@@ -583,11 +583,17 @@ AdvSceneSwitcher.action.variable.type.increment="Increment"
AdvSceneSwitcher.action.variable.type.decrement="Decrement"
AdvSceneSwitcher.action.variable.type.setActionValue="Set to action value"
AdvSceneSwitcher.action.variable.type.setConditionValue="Set to condition value"
AdvSceneSwitcher.action.variable.type.roundToInt="Round to nearest integer"
AdvSceneSwitcher.action.variable.type.subString="Set to substring of current value"
AdvSceneSwitcher.action.variable.subString.begin="Beginning"
AdvSceneSwitcher.action.variable.subString.all="All"
AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}"
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}} Substring size:{{subStringSize}}"
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
; Transition Tab

View File

@@ -155,6 +155,7 @@ void SwitcherData::Thread()
while (true) {
std::unique_lock<std::mutex> lock(m);
mainLoopLock = &lock;
bool match = false;
OBSWeakSource scene;
@@ -230,19 +231,6 @@ void SwitcherData::Thread()
ClearWebsocketMessages();
// After this point we will call frontend functions like
// obs_frontend_set_current_scene() and
// obs_frontend_set_current_transition()
//
// During this time SaveSceneSwitcher() could be called
// leading to a deadlock with the frontend function being stuck
// in QMetaObject::invokeMethod() holding the mutex and
// OBS being stuck in SaveSceneSwitcher().
//
// So we have to unlock() risking race conditions as these are
// less frequent than the above described deadlock
lock.unlock();
if (match) {
if (macroMatch) {
runMacros();

View File

@@ -255,11 +255,28 @@ QString getDefaultSaveLocation()
{
QString desktopPath = QStandardPaths::writableLocation(
QStandardPaths::DesktopLocation);
auto scName = obs_frontend_get_current_scene_collection();
QString sceneCollectionName(scName);
bfree(scName);
auto timestamp = QDateTime::currentDateTime();
return desktopPath + "/adv-ss-" + sceneCollectionName + "-" +
auto path = desktopPath + "/adv-ss-" + sceneCollectionName + "-" +
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
// Check if scene collection name contains invalid path characters
QFile file(path);
if (file.exists()) {
return path;
}
bool validPath = file.open(QIODevice::WriteOnly);
if (validPath) {
file.remove();
return path;
}
return desktopPath + "/adv-ss-" +
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
}
@@ -638,10 +655,9 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
obs_data_set_bool(obj, "tansitionOverrideOverride",
transitionOverrideOverride);
obs_data_set_default_bool(obj, "adjustActiveTransitionType",
adjustActiveTransitionType);
obs_data_set_bool(obj, "adjustActiveTransitionType",
adjustActiveTransitionType);
obs_data_set_string(obj, "lastImportPath", lastImportPath.c_str());
}
@@ -724,6 +740,12 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
adjustActiveTransitionType =
obs_data_get_bool(obj, "adjustActiveTransitionType");
if (!transitionOverrideOverride && !adjustActiveTransitionType) {
blog(LOG_INFO,
"reset transition behaviour to adjust active transition type");
adjustActiveTransitionType = true;
}
lastImportPath = obs_data_get_string(obj, "lastImportPath");
}

View File

@@ -11,37 +11,39 @@ bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
{MacroActionSwitchScene::Create, MacroActionSwitchSceneEdit::Create,
"AdvSceneSwitcher.action.switchScene"});
void waitForTransitionChange(OBSWeakSource &transition)
static void waitForTransitionChange(OBSWeakSource &transition,
std::unique_lock<std::mutex> *lock,
Macro *macro)
{
const auto time = 100ms;
obs_source_t *source = obs_weak_source_get_source(transition);
std::unique_lock<std::mutex> lock(switcher->m);
bool stillTransitioning = true;
while (stillTransitioning && !switcher->abortMacroWait) {
switcher->macroTransitionCv.wait_for(lock, time);
while (stillTransitioning && !switcher->abortMacroWait &&
!macro->GetStop()) {
switcher->macroTransitionCv.wait_for(*lock, time);
float t = obs_transition_get_time(source);
stillTransitioning = t < 1.0f && t > 0.0f;
}
obs_source_release(source);
}
void waitForTransitionChangeFixedDuration(int duration)
static void waitForTransitionChangeFixedDuration(
int duration, std::unique_lock<std::mutex> *lock, Macro *macro)
{
duration += 200; // It seems to be necessary to add a small buffer
auto time = std::chrono::high_resolution_clock::now() +
std::chrono::milliseconds(duration);
switcher->abortMacroWait = false;
std::unique_lock<std::mutex> lock(switcher->m);
while (!switcher->abortMacroWait) {
if (switcher->macroTransitionCv.wait_until(lock, time) ==
while (!switcher->abortMacroWait && !macro->GetStop()) {
if (switcher->macroTransitionCv.wait_until(*lock, time) ==
std::cv_status::timeout) {
break;
}
}
}
int getTransitionOverrideDuration(OBSWeakSource &scene)
static int getTransitionOverrideDuration(OBSWeakSource &scene)
{
int duration = 0;
obs_source_t *source = obs_weak_source_get_source(scene);
@@ -55,7 +57,7 @@ int getTransitionOverrideDuration(OBSWeakSource &scene)
return duration;
}
bool isUsingFixedLengthTransition(const OBSWeakSource &transition)
static bool isUsingFixedLengthTransition(const OBSWeakSource &transition)
{
obs_source_t *source = obs_weak_source_get_source(transition);
bool ret = obs_transition_fixed(source);
@@ -63,7 +65,7 @@ bool isUsingFixedLengthTransition(const OBSWeakSource &transition)
return ret;
}
OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
{
OBSWeakSource transition;
obs_source_t *source = obs_weak_source_get_source(scene);
@@ -75,8 +77,8 @@ OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
return transition;
}
int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
double duration)
static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
double duration)
{
OBSWeakSource transition = t;
if (!switcher->transitionOverrideOverride) {
@@ -97,6 +99,37 @@ int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
return obs_frontend_get_transition_duration();
}
bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
OBSWeakSource &transition)
{
const int expectedTransitionDuration = getExpectedTransitionDuration(
scene, transition, _duration.seconds);
switcher->abortMacroWait = false;
bool isInMainLoop = QThread::currentThread() == switcher->th;
if (isInMainLoop) {
if (expectedTransitionDuration < 0) {
waitForTransitionChange(transition, switcher->GetLock(),
GetMacro());
} else {
waitForTransitionChangeFixedDuration(
expectedTransitionDuration, switcher->GetLock(),
GetMacro());
}
} else {
std::mutex temp;
std::unique_lock<std::mutex> lock(temp);
if (expectedTransitionDuration < 0) {
waitForTransitionChange(transition, &lock, GetMacro());
} else {
waitForTransitionChangeFixedDuration(
expectedTransitionDuration, &lock, GetMacro());
}
}
return !switcher->abortMacroWait;
}
bool MacroActionSwitchScene::PerformAction()
{
auto scene = _scene.GetScene();
@@ -104,16 +137,7 @@ bool MacroActionSwitchScene::PerformAction()
switchScene({scene, transition, (int)(_duration.seconds * 1000)},
obs_frontend_preview_program_mode_active());
if (_blockUntilTransitionDone && scene) {
const int expectedTransitionDuration =
getExpectedTransitionDuration(scene, transition,
_duration.seconds);
if (expectedTransitionDuration < 0) {
waitForTransitionChange(transition);
} else {
waitForTransitionChangeFixedDuration(
expectedTransitionDuration);
}
return !switcher->abortMacroWait;
return WaitForTransition(scene, transition);
}
return true;
}

View File

@@ -26,7 +26,7 @@ public:
bool _blockUntilTransitionDone = true;
private:
const char *getType() { return "MacroActionSwitchScene"; }
bool WaitForTransition(OBSWeakSource &scene, OBSWeakSource &transition);
static bool _registered;
static const std::string id;

View File

@@ -45,6 +45,8 @@ bool MacroActionScreenshot::PerformAction()
case MacroActionScreenshot::TargetType::SCENE:
source = _scene.GetScene(false);
break;
case MacroActionScreenshot::TargetType::MAIN_OUTPUT:
break;
}
switch (_saveType) {
@@ -73,8 +75,7 @@ void MacroActionScreenshot::LogAction() const
_scene.ToString(true).c_str());
break;
case MacroActionScreenshot::TargetType::MAIN_OUTPUT:
vblog(LOG_INFO, "trigger screenshot of main output",
_scene.ToString(true).c_str());
vblog(LOG_INFO, "trigger screenshot of main output");
break;
}
}

View File

@@ -25,6 +25,10 @@ static std::map<MacroActionVariable::Type, std::string> actionTypes = {
"AdvSceneSwitcher.action.variable.type.setConditionValue"},
{MacroActionVariable::Type::SET_ACTION_VALUE,
"AdvSceneSwitcher.action.variable.type.setActionValue"},
{MacroActionVariable::Type::ROUND_TO_INT,
"AdvSceneSwitcher.action.variable.type.roundToInt"},
{MacroActionVariable::Type::SUBSTRING,
"AdvSceneSwitcher.action.variable.type.subString"},
};
static void apppend(Variable &var, const std::string &value)
@@ -51,6 +55,46 @@ MacroActionVariable::~MacroActionVariable()
DecrementCurrentSegmentVariableRef();
}
void MacroActionVariable::HandleIndexSubString(Variable *var)
{
const auto curValue = var->Value();
try {
if (_subStringSize == 0) {
var->SetValue(curValue.substr(_subStringStart));
return;
}
var->SetValue(curValue.substr(_subStringStart, _subStringSize));
} catch (const std::out_of_range &) {
vblog(LOG_WARNING,
"invalid start index \"%d\" selected for substring of \"%s\" of variable \"%s\"",
_subStringStart, curValue.c_str(), var->Name().c_str());
}
}
void MacroActionVariable::HandleRegexSubString(Variable *var)
{
const auto curValue = var->Value();
auto regex = _regex.GetRegularExpression(_regexPattern);
if (!regex.isValid()) {
return;
}
auto it = regex.globalMatch(QString::fromStdString(curValue));
for (int idx = 0; idx < _regexMatchIdx; idx++) {
if (!it.hasNext()) {
return;
}
it.next();
}
if (!it.hasNext()) {
return;
}
auto match = it.next();
var->SetValue(match.captured(0).toStdString());
}
bool MacroActionVariable::PerformAction()
{
auto var = GetVariableByName(_variableName);
@@ -95,6 +139,22 @@ bool MacroActionVariable::PerformAction()
var->SetValue(segment->GetVariableValue());
break;
}
case Type::ROUND_TO_INT: {
double curValue;
if (!var->DoubleValue(curValue)) {
return true;
}
var->SetValue(std::to_string(int(std::round(curValue))));
return true;
}
case Type::SUBSTRING: {
if (_regex.Enabled()) {
HandleRegexSubString(var);
return true;
}
HandleIndexSubString(var);
return true;
}
}
return true;
@@ -109,6 +169,11 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
obs_data_set_double(obj, "numValue", _numValue);
obs_data_set_int(obj, "condition", static_cast<int>(_type));
obs_data_set_int(obj, "segmentIdx", GetSegmentIndexValue());
obs_data_set_int(obj, "subStringStart", _subStringStart);
obs_data_set_int(obj, "subStringSize", _subStringSize);
obs_data_set_string(obj, "regexPattern", _regexPattern.c_str());
obs_data_set_int(obj, "regexMatchIdx", _regexMatchIdx);
_regex.Save(obj);
return true;
}
@@ -121,6 +186,11 @@ bool MacroActionVariable::Load(obs_data_t *obj)
_numValue = obs_data_get_double(obj, "numValue");
_type = static_cast<Type>(obs_data_get_int(obj, "condition"));
_segmentIdxLoadValue = obs_data_get_int(obj, "segmentIdx");
_subStringStart = obs_data_get_int(obj, "subStringStart");
_subStringSize = obs_data_get_int(obj, "subStringSize");
_regex.Load(obj);
_regexPattern = obs_data_get_string(obj, "regexPattern");
_regexMatchIdx = obs_data_get_int(obj, "regexMatchIdx");
return true;
}
@@ -152,11 +222,11 @@ void MacroActionVariable::SetSegmentIndexValue(int value)
std::shared_ptr<MacroSegment> segment;
if (_type == Type::SET_CONDITION_VALUE) {
if (value < m->Conditions().size()) {
if (value < (int)m->Conditions().size()) {
segment = m->Conditions().at(value);
}
} else if (_type == Type::SET_ACTION_VALUE) {
if (value < m->Actions().size()) {
if (value < (int)m->Actions().size()) {
segment = m->Actions().at(value);
}
}
@@ -225,7 +295,15 @@ MacroActionVariableEdit::MacroActionVariableEdit(
_numValue(new QDoubleSpinBox()),
_segmentIdx(new QSpinBox()),
_segmentValueStatus(new QLabel()),
_segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1))
_segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1)),
_substringLayout(new QVBoxLayout()),
_subStringIndexEntryLayout(new QHBoxLayout()),
_subStringRegexEntryLayout(new QHBoxLayout()),
_subStringStart(new QSpinBox()),
_subStringSize(new QSpinBox()),
_regex(new RegexConfigWidget(parent)),
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
_regexMatchIdx(new QSpinBox())
{
_numValue->setMinimum(-9999999999);
_numValue->setMaximum(9999999999);
@@ -233,6 +311,17 @@ MacroActionVariableEdit::MacroActionVariableEdit(
_segmentIdx->setMaximum(99);
_segmentIdx->setSpecialValueText("-");
_segmentValue->setReadOnly(true);
_subStringStart->setMinimum(1);
_subStringStart->setMaximum(99999);
_subStringStart->setSpecialValueText(obs_module_text(
"AdvSceneSwitcher.action.variable.subString.begin"));
_subStringSize->setMinimum(0);
_subStringSize->setMaximum(99999);
_subStringSize->setSpecialValueText(obs_module_text(
"AdvSceneSwitcher.action.variable.subString.all"));
_regexMatchIdx->setMinimum(1);
_regexMatchIdx->setMaximum(999);
_regexMatchIdx->setSuffix(".");
populateTypeSelection(_actions);
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
@@ -249,6 +338,16 @@ MacroActionVariableEdit::MacroActionVariableEdit(
SLOT(SegmentIndexChanged(int)));
QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
SLOT(MacroSegmentOrderChanged()));
QWidget::connect(_subStringStart, SIGNAL(valueChanged(int)), this,
SLOT(SubStringStartChanged(int)));
QWidget::connect(_subStringSize, SIGNAL(valueChanged(int)), this,
SLOT(SubStringSizeChanged(int)));
QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this,
SLOT(RegexChanged(RegexConfig)));
QWidget::connect(_regexPattern, SIGNAL(textChanged()), this,
SLOT(RegexPatternChanged()));
QWidget::connect(_regexMatchIdx, SIGNAL(valueChanged(int)), this,
SLOT(RegexMatchIdxChanged(int)));
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{variables}}", _variables},
@@ -257,13 +356,36 @@ MacroActionVariableEdit::MacroActionVariableEdit(
{"{{strValue}}", _strValue},
{"{{numValue}}", _numValue},
{"{{segmentIndex}}", _segmentIdx},
{"{{subStringStart}}", _subStringStart},
{"{{subStringSize}}", _subStringSize},
{"{{regexMatchIdx}}", _regexMatchIdx},
};
auto entryLayout = new QHBoxLayout;
placeWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"),
entryLayout, widgetPlaceholders);
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.action.variable.entry.substringIndex"),
_subStringIndexEntryLayout, widgetPlaceholders);
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.action.variable.entry.substringRegex"),
_subStringRegexEntryLayout, widgetPlaceholders);
auto regexConfigLayout = new QHBoxLayout;
regexConfigLayout->addWidget(_regex);
regexConfigLayout->addStretch();
_substringLayout->addLayout(_subStringIndexEntryLayout);
_substringLayout->addLayout(_subStringRegexEntryLayout);
_substringLayout->addWidget(_regexPattern);
_substringLayout->addLayout(regexConfigLayout);
auto layout = new QVBoxLayout;
layout->addLayout(entryLayout);
layout->addLayout(_substringLayout);
layout->addWidget(_segmentValueStatus);
layout->addWidget(_segmentValue);
setLayout(layout);
@@ -290,6 +412,12 @@ void MacroActionVariableEdit::UpdateEntryData()
_strValue->setPlainText(QString::fromStdString(_entryData->_strValue));
_numValue->setValue(_entryData->_numValue);
_segmentIdx->setValue(_entryData->GetSegmentIndexValue() + 1);
_subStringStart->setValue(_entryData->_subStringStart + 1);
_subStringSize->setValue(_entryData->_subStringSize);
_regex->SetRegexConfig(_entryData->_regex);
_regexPattern->setPlainText(
QString::fromStdString(_entryData->_regexPattern));
_regexMatchIdx->setValue(_entryData->_regexMatchIdx + 1);
SetWidgetVisibility();
}
@@ -399,13 +527,13 @@ void MacroActionVariableEdit::UpdateSegmentVariableValue()
std::shared_ptr<MacroSegment> segment;
if (_entryData->_type == MacroActionVariable::Type::SET_ACTION_VALUE) {
const auto &actions = m->Actions();
if (index < actions.size()) {
if (index < (int)actions.size()) {
segment = actions.at(index);
}
} else if (_entryData->_type ==
MacroActionVariable::Type::SET_CONDITION_VALUE) {
const auto &conditions = m->Conditions();
if (index < conditions.size()) {
if (index < (int)conditions.size()) {
segment = conditions.at(index);
}
}
@@ -454,6 +582,59 @@ void MacroActionVariableEdit::MacroSegmentOrderChanged()
_segmentIdx->setValue(_entryData->GetSegmentIndexValue() + 1);
}
void MacroActionVariableEdit::SubStringStartChanged(int val)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_subStringStart = val - 1;
}
void MacroActionVariableEdit::SubStringSizeChanged(int val)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_subStringSize = val;
}
void MacroActionVariableEdit::RegexChanged(RegexConfig conf)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_regex = conf;
SetWidgetVisibility();
}
void MacroActionVariableEdit::RegexPatternChanged()
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_regexPattern = _regexPattern->toPlainText().toStdString();
adjustSize();
}
void MacroActionVariableEdit::RegexMatchIdxChanged(int val)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_regexMatchIdx = val - 1;
}
void MacroActionVariableEdit::MarkSelectedSegment()
{
if (switcher->disableHints) {
@@ -472,14 +653,14 @@ void MacroActionVariableEdit::MarkSelectedSegment()
if (_entryData->_type == MacroActionVariable::Type::SET_ACTION_VALUE) {
const auto &actions = m->Actions();
if (index >= actions.size()) {
if (index >= (int)actions.size()) {
return;
}
AdvSceneSwitcher::window->HighlightAction(
index, QColor(Qt::lightGray));
} else {
const auto &conditions = m->Conditions();
if (index >= conditions.size()) {
if (index >= (int)conditions.size()) {
return;
}
AdvSceneSwitcher::window->HighlightCondition(
@@ -520,6 +701,15 @@ void MacroActionVariableEdit::SetWidgetVisibility()
MacroActionVariable::Type::SET_ACTION_VALUE ||
_entryData->_type ==
MacroActionVariable::Type::SET_CONDITION_VALUE);
setLayoutVisible(_substringLayout,
_entryData->_type ==
MacroActionVariable::Type::SUBSTRING);
if (_entryData->_type == MacroActionVariable::Type::SUBSTRING) {
bool showRegex = _entryData->_regex.Enabled();
setLayoutVisible(_subStringIndexEntryLayout, !showRegex);
setLayoutVisible(_subStringRegexEntryLayout, showRegex);
_regexPattern->setVisible(showRegex);
}
adjustSize();
updateGeometry();

View File

@@ -1,6 +1,7 @@
#pragma once
#include "macro-action-edit.hpp"
#include "resizing-text-edit.hpp"
#include "regex-config.hpp"
#include "variable.hpp"
class MacroActionVariable : public MacroAction {
@@ -28,6 +29,8 @@ public:
DECREMENT,
SET_CONDITION_VALUE,
SET_ACTION_VALUE,
ROUND_TO_INT,
SUBSTRING,
};
Type _type = Type::SET_FIXED_VALUE;
@@ -35,9 +38,16 @@ public:
std::string _variable2Name = "";
std::string _strValue = "";
double _numValue = 0;
int _subStringStart = 0;
int _subStringSize = 0;
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
std::string _regexPattern = ".*";
int _regexMatchIdx = 0;
private:
void DecrementCurrentSegmentVariableRef();
void HandleIndexSubString(Variable *);
void HandleRegexSubString(Variable *);
std::weak_ptr<MacroSegment> _macroSegment;
int _segmentIdxLoadValue = -1;
@@ -70,6 +80,11 @@ private slots:
void SegmentIndexChanged(int val);
void UpdateSegmentVariableValue();
void MacroSegmentOrderChanged();
void SubStringStartChanged(int val);
void SubStringSizeChanged(int val);
void RegexChanged(RegexConfig conf);
void RegexPatternChanged();
void RegexMatchIdxChanged(int val);
signals:
void HeaderInfoChanged(const QString &);
@@ -79,10 +94,18 @@ protected:
VariableSelection *_variables2;
QComboBox *_actions;
ResizingPlainTextEdit *_strValue;
QSpinBox *_segmentIdx;
QDoubleSpinBox *_numValue;
QSpinBox *_segmentIdx;
QLabel *_segmentValueStatus;
ResizingPlainTextEdit *_segmentValue;
QVBoxLayout *_substringLayout;
QHBoxLayout *_subStringIndexEntryLayout;
QHBoxLayout *_subStringRegexEntryLayout;
QSpinBox *_subStringStart;
QSpinBox *_subStringSize;
RegexConfigWidget *_regex;
ResizingPlainTextEdit *_regexPattern;
QSpinBox *_regexMatchIdx;
std::shared_ptr<MacroActionVariable> _entryData;
private:

View File

@@ -19,6 +19,17 @@ static std::map<WaitType, std::string> waitTypes = {
static std::random_device rd;
static std::default_random_engine re(rd());
static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
std::chrono::high_resolution_clock::time_point &time)
{
while (!switcher->abortMacroWait && !macro->GetStop()) {
if (switcher->macroWaitCv.wait_until(*lock, time) ==
std::cv_status::timeout) {
break;
}
}
}
bool MacroActionWait::PerformAction()
{
double sleepDuration;
@@ -39,14 +50,15 @@ bool MacroActionWait::PerformAction()
auto time = std::chrono::high_resolution_clock::now() +
std::chrono::milliseconds((int)(sleepDuration * 1000));
auto macro = GetMacro();
switcher->abortMacroWait = false;
std::unique_lock<std::mutex> lock(switcher->m);
while (!switcher->abortMacroWait && !macro->GetStop()) {
if (switcher->macroWaitCv.wait_until(lock, time) ==
std::cv_status::timeout) {
break;
}
bool isInMainLoop = QThread::currentThread() == switcher->th;
if (isInMainLoop) {
waitHelper(switcher->GetLock(), GetMacro(), time);
} else {
std::mutex temp;
std::unique_lock<std::mutex> lock(temp);
waitHelper(&lock, GetMacro(), time);
}
return !switcher->abortMacroWait;

View File

@@ -159,7 +159,7 @@ bool MacroConditionFile::CheckCondition()
SetVariableValue(ret ? "true" : "false");
}
return false;
return ret;
}
bool MacroConditionFile::Save(obs_data_t *obj) const

View File

@@ -401,9 +401,9 @@ static void populateSourceTypes(QComboBox *list)
MacroConditionMediaEdit::MacroConditionMediaEdit(
QWidget *parent, std::shared_ptr<MacroConditionMedia> entryData)
: QWidget(parent),
_sourceTypes(new QComboBox()),
_scenes(new SceneSelectionWidget(window(), true, true, true, true,
true)),
_sourceTypes(new QComboBox()),
_sources(new SourceSelectionWidget(this, QStringList(), true)),
_states(new QComboBox()),
_timeRestrictions(new QComboBox()),

View File

@@ -53,7 +53,7 @@ bool MacroConditionScene::CheckCondition()
auto current = obs_frontend_get_current_scene();
auto weak = obs_source_get_weak_source(current);
bool match = weak == _scene.GetScene(false);
SetVariableValue(obs_source_get_name(current));
SetVariableValue(GetWeakSourceName(weak));
obs_weak_source_release(weak);
obs_source_release(current);
return match;

View File

@@ -96,6 +96,10 @@ bool MacroConditionVariable::CompareVariables()
return validNumbers && val1 < val2;
case MacroConditionVariable::Type::GREATER_THAN_VARIABLE:
return validNumbers && val1 > val2;
default:
blog(LOG_WARNING,
"Unexpected call of %s with condition type %d", __func__,
static_cast<int>(_type));
}
return false;

View File

@@ -9,7 +9,7 @@
#include <QScrollBar>
MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue)
: _supportsVariableValue(supportsVariableValue), _macro(m)
: _macro(m), _supportsVariableValue(supportsVariableValue)
{
}

View File

@@ -18,6 +18,8 @@ MacroTreeItem::MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macroItem,
: _tree(tree), _highlight(highlight), _macro(macroItem)
{
setAttribute(Qt::WA_TranslucentBackground);
// This is necessary for some theses to display active selections properly
setStyleSheet("background: none");
auto name = _macro->Name();
bool macroPaused = _macro->Paused();
@@ -501,10 +503,13 @@ Qt::ItemFlags MacroTreeModel::flags(const QModelIndex &index) const
return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled;
}
std::shared_ptr<Macro> item =
_macros[ModelIndexToMacroIndex(index.row(), _macros)];
std::shared_ptr<Macro> item;
try {
item = _macros.at(ModelIndexToMacroIndex(index.row(), _macros));
} catch (const std::out_of_range &) {
return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled;
}
bool isGroup = item->IsGroup();
return QAbstractListModel::flags(index) | Qt::ItemIsEditable |
Qt::ItemIsDragEnabled |
(isGroup ? Qt::ItemIsDropEnabled : Qt::NoItemFlags);

View File

@@ -741,9 +741,6 @@ bool SwitcherData::checkMacros()
bool SwitcherData::runMacros()
{
// TODO: Don't rely on creating a copy of each macro once new frontend
// events are available - see:
// https://github.com/obsproject/obs-studio/commit/feda1aaa283e8a99f6ba1159cfe6b9c1f2934a61
for (auto m : macros) {
if (m->Matched()) {
vblog(LOG_INFO, "running macro: %s", m->Name().c_str());

View File

@@ -4,7 +4,6 @@
#include "utility.hpp"
#include <screenshot-helper.hpp>
#include <condition_variable>
PreviewDialog::PreviewDialog(QWidget *parent, int delay)
: QDialog(parent),
@@ -119,6 +118,7 @@ void PreviewDialog::SelectArea()
void PreviewDialog::Stop()
{
_stop = true;
_cv.notify_all();
if (_thread.joinable()) {
_thread.join();
}
@@ -189,13 +189,12 @@ void PreviewDialog::Start()
void PreviewDialog::CheckForMatchLoop()
{
std::condition_variable cv;
while (!_stop) {
std::unique_lock<std::mutex> lock(_mtx);
auto source = obs_weak_source_get_source(_video.GetVideo());
ScreenshotHelper screenshot(source);
obs_source_release(source);
cv.wait_for(lock, std::chrono::milliseconds(_delay));
_cv.wait_for(lock, std::chrono::milliseconds(_delay));
if (_stop || isHidden()) {
return;
}

View File

@@ -12,6 +12,7 @@
#include <thread>
#include <mutex>
#include <condition_variable>
class PreviewDialog : public QDialog {
Q_OBJECT
@@ -62,6 +63,7 @@ private:
std::atomic_bool _selectingArea = {false};
std::mutex _mtx;
std::condition_variable _cv;
std::thread _thread;
std::atomic_bool _stop = {true};

View File

@@ -90,6 +90,8 @@ struct SwitcherData {
std::condition_variable cv;
std::mutex m;
std::unique_lock<std::mutex> *mainLoopLock;
bool transitionActive = false;
bool waitForTransition = false;
bool stop = false;
@@ -251,6 +253,7 @@ struct SwitcherData {
void Thread();
void Start();
void Stop();
std::unique_lock<std::mutex> *GetLock() { return mainLoopLock; }
void setWaitScene();
bool sceneChangedDuringWait();

View File

@@ -47,6 +47,13 @@ RegexConfig::GetRegularExpression(const std::string &expr) const
return GetRegularExpression(QString::fromStdString(expr));
}
RegexConfig RegexConfig::PartialMatchRegexConfig()
{
RegexConfig conf;
conf._partialMatch = true;
return conf;
}
RegexConfigWidget::RegexConfigWidget(QWidget *parent)
: QWidget(parent),
_openSettings(new QPushButton()),

View File

@@ -25,6 +25,8 @@ public:
QRegularExpression GetRegularExpression(const QString &) const;
QRegularExpression GetRegularExpression(const std::string &) const;
static RegexConfig PartialMatchRegexConfig();
private:
bool _enable = false;
bool _partialMatch = false;

View File

@@ -103,6 +103,10 @@ QStringList GetVariablesNameList()
void VariableResolvingString::Resolve()
{
if (switcher->variables.empty()) {
_resolvedValue = _value;
return;
}
if (_lastResolve == lastVariableChange) {
return;
}
@@ -131,6 +135,7 @@ void VariableResolvingString::operator=(const char *value)
void VariableResolvingString::Load(obs_data_t *obj, const char *name)
{
_value = obs_data_get_string(obj, name);
Resolve();
}
void VariableResolvingString::Save(obs_data_t *obj, const char *name) const