pax_global_header00006660000000000000000000000064144042102600014503gustar00rootroot0000000000000052 comment=7b446b1a5a294902bc751dba23334362f8589884 obs-command-source-0.4.0/000077500000000000000000000000001440421026000152015ustar00rootroot00000000000000obs-command-source-0.4.0/.clang-format000066400000000000000000000063271440421026000175640ustar00rootroot00000000000000# please use clang-format version 8 or later Standard: Cpp11 AccessModifierOffset: -8 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true #AllowAllArgumentsOnNextLine: false # requires clang-format 9 #AllowAllConstructorInitializersOnNextLine: false # requires clang-format 9 AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false #AllowShortLambdasOnASingleLine: Inline # requires clang-format 9 AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false AfterStruct: true AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: true IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeColon BreakStringLiterals: false # apparently unpredictable ColumnLimit: 120 CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false FixNamespaceComments: false ForEachMacros: - 'json_object_foreach' - 'json_object_foreach_safe' - 'json_array_foreach' IncludeBlocks: Preserve IndentCaseLabels: false IndentPPDirectives: None IndentWidth: 8 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: true MaxEmptyLinesToKeep: 1 NamespaceIndentation: None #ObjCBinPackProtocolList: Auto # requires clang-format 7 ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 10 PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakComment: 10 PenaltyBreakFirstLessLess: 0 PenaltyBreakString: 10 PenaltyExcessCharacter: 100 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right ReflowComments: false SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: false #SpaceAfterLogicalNot: false # requires clang-format 9 SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true #SpaceBeforeCtorInitializerColon: true # requires clang-format 7 #SpaceBeforeInheritanceColon: true # requires clang-format 7 SpaceBeforeParens: ControlStatements #SpaceBeforeRangeBasedForLoopColon: true # requires clang-format 7 SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: false SpacesInParentheses: false SpacesInSquareBrackets: false #StatementMacros: # requires clang-format 8 # - 'Q_OBJECT' TabWidth: 8 #TypenameMacros: # requires clang-format 9 # - 'DARRAY' UseTab: ForContinuationAndIndentation --- Language: ObjC obs-command-source-0.4.0/.github/000077500000000000000000000000001440421026000165415ustar00rootroot00000000000000obs-command-source-0.4.0/.github/containers/000077500000000000000000000000001440421026000207065ustar00rootroot00000000000000obs-command-source-0.4.0/.github/containers/fedora-common/000077500000000000000000000000001440421026000234345ustar00rootroot00000000000000obs-command-source-0.4.0/.github/containers/fedora-common/build.sh000077500000000000000000000024661440421026000251020ustar00rootroot00000000000000#! /bin/bash set -ex docker_image="$1" rpmbuild="$2" PLUGIN_NAME=$(awk '/^project\(/{print gensub(/project\(([^ ()]*).*/, "\\1", 1, $0)}' CMakeLists.txt) eval $(git describe --tag --always --long | awk ' BEGIN { VERSION="unknown"; RELEASE=0; } { if (match($0, /^(.*)-([0-9]*)-g[0-9a-f]*$/, aa)) { VERSION = aa[1] RELEASE = aa[2] } } END { VERSION = gensub(/-(alpha|beta|rc)/, "~\\1", 1, VERSION); gsub(/["'\''-]/, ".", VERSION); printf("VERSION='\''%s'\'' RELEASE=%d\n", VERSION, RELEASE + 1); }') rm -rf $rpmbuild mkdir -p $rpmbuild/{BUILD,BUILDROOT,SRPMS,SOURCES,SPECS,RPMS} rpmbuild="$(cd $rpmbuild && pwd -P)" chmod a+w $rpmbuild/{BUILD,BUILDROOT,SRPMS,RPMS} test -x /usr/sbin/selinuxenabled && /usr/sbin/selinuxenabled && chcon -Rt container_file_t $rpmbuild # Prepare files sed \ -e "s/@PLUGIN_NAME@/$PLUGIN_NAME/g" \ -e "s/@VERSION@/$VERSION/g" \ -e "s/@RELEASE@/$RELEASE/g" \ < ci/plugin.spec \ > $rpmbuild/SPECS/$PLUGIN_NAME.spec git archive --format=tar --prefix=$PLUGIN_NAME-$VERSION/ HEAD | bzip2 > $rpmbuild/SOURCES/$PLUGIN_NAME-$VERSION.tar.bz2 docker run -v $rpmbuild:/home/rpm/rpmbuild $docker_image bash -c " sudo dnf builddep -y ~/rpmbuild/SPECS/$PLUGIN_NAME.spec && sudo chown 0.0 ~/rpmbuild/SOURCES/* && sudo chown 0.0 ~/rpmbuild/SPECS/* && rpmbuild -ba ~/rpmbuild/SPECS/$PLUGIN_NAME.spec " obs-command-source-0.4.0/.github/containers/fedora36/000077500000000000000000000000001440421026000223175ustar00rootroot00000000000000obs-command-source-0.4.0/.github/containers/fedora36/Dockerfile000066400000000000000000000007531440421026000243160ustar00rootroot00000000000000FROM fedora:36 RUN dnf install -y rpm-build python3-dnf-plugins-core && dnf clean all # https://docs.fedoraproject.org/en-US/quick-docs/setup_rpmfusion/ RUN dnf install -y https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm && dnf clean all RUN dnf install -y obs-studio obs-studio-devel && dnf clean all RUN useradd -s /bin/bash -m rpm RUN echo >> /etc/sudoers RUN echo "rpm ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers USER rpm WORKDIR /home/rpm obs-command-source-0.4.0/.github/containers/fedora36/build.sh000077500000000000000000000002541440421026000237560ustar00rootroot00000000000000#! /bin/bash set -ex .github/containers/fedora-common/build.sh obs-plugin-build/fedora36 fedora36-rpmbuild echo 'FILE_NAME=fedora36-rpmbuild/*RPMS/**/*.rpm' >> $GITHUB_ENV obs-command-source-0.4.0/.github/containers/fedora37/000077500000000000000000000000001440421026000223205ustar00rootroot00000000000000obs-command-source-0.4.0/.github/containers/fedora37/Dockerfile000066400000000000000000000007531440421026000243170ustar00rootroot00000000000000FROM fedora:37 RUN dnf install -y rpm-build python3-dnf-plugins-core && dnf clean all # https://docs.fedoraproject.org/en-US/quick-docs/setup_rpmfusion/ RUN dnf install -y https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm && dnf clean all RUN dnf install -y obs-studio obs-studio-devel && dnf clean all RUN useradd -s /bin/bash -m rpm RUN echo >> /etc/sudoers RUN echo "rpm ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers USER rpm WORKDIR /home/rpm obs-command-source-0.4.0/.github/containers/fedora37/build.sh000077500000000000000000000002541440421026000237570ustar00rootroot00000000000000#! /bin/bash set -ex .github/containers/fedora-common/build.sh obs-plugin-build/fedora37 fedora37-rpmbuild echo 'FILE_NAME=fedora37-rpmbuild/*RPMS/**/*.rpm' >> $GITHUB_ENV obs-command-source-0.4.0/.github/workflows/000077500000000000000000000000001440421026000205765ustar00rootroot00000000000000obs-command-source-0.4.0/.github/workflows/clang-format.yml000066400000000000000000000012161440421026000236730ustar00rootroot00000000000000name: Clang Format Check on: push: branches: [ main ] pull_request: branches: [ main ] jobs: clang: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Clang run: | sudo apt-get install -y clang-format-12 clang-format -i -fallback-style=none $(git ls-files | grep '\.\(c\|h\)$') - name: Check # Build your program with the given configuration run: | dirty=$(git ls-files --modified) set +x if [[ $dirty ]]; then git diff echo "Error: File(s) are not properly formatted." echo "$dirty" exit 1 fi obs-command-source-0.4.0/.github/workflows/docker-build.yml000066400000000000000000000040501440421026000236640ustar00rootroot00000000000000name: Plugin Build on Docker on: push: paths-ignore: - '**.md' branches: - main tags: - '*' pull_request: paths-ignore: - '**.md' branches: - main env: artifactName: ${{ contains(github.ref_name, '/') && 'docker-artifact' || github.ref_name }}-rpm jobs: docker_build: runs-on: ubuntu-latest strategy: fail-fast: false matrix: target: - fedora36 - fedora37 defaults: run: shell: bash env: target: ${{ matrix.target }} steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 submodules: recursive - name: Restore docker from cache id: docker-cache uses: actions/cache/restore@v3 with: path: ${{ github.workspace }}/docker-cache key: docker-cache-${{ matrix.target }}-${{ hashFiles(format('.github/containers/{0}/Dockerfile', matrix.target)) }} - name: Build environment if: ${{ steps.docker-cache.outputs.cache-hit != 'true' }} run: | docker build -t obs-plugin-build/$target .github/containers/$target mkdir -p docker-cache docker save obs-plugin-build/$target | gzip > docker-cache/obs-plugin-build-$target.tar.gz - name: Save docker to cache uses: actions/cache/save@v3 if: ${{ steps.docker-cache.outputs.cache-hit != 'true' }} with: path: ${{ github.workspace }}/docker-cache key: docker-cache-${{ matrix.target }}-${{ hashFiles(format('.github/containers/{0}/Dockerfile', matrix.target)) }} - name: Extract cached environment if: ${{ steps.docker-cache.outputs.cache-hit == 'true' }} run: | zcat docker-cache/obs-plugin-build-$target.tar.gz | docker load - name: Build package run: .github/containers/$target/build.sh - name: Upload artifact uses: actions/upload-artifact@v3 with: name: ${{ env.artifactName }} path: '${{ env.FILE_NAME }}' obs-command-source-0.4.0/.github/workflows/main.yml000066400000000000000000000257301440421026000222540ustar00rootroot00000000000000name: Plugin Build on: push: paths-ignore: - '**.md' branches: - main tags: - '*' pull_request: paths-ignore: - '**.md' branches: - main env: artifactName: ${{ contains(github.ref_name, '/') && 'artifact' || github.ref_name }} qt: false jobs: linux_build: runs-on: ${{ matrix.ubuntu }} strategy: fail-fast: false matrix: obs: [27, 28] ubuntu: ['ubuntu-20.04'] defaults: run: shell: bash steps: - name: Checkout uses: actions/checkout@v3 with: submodules: recursive - name: Download obs-studio development environment id: obsdeps uses: norihiro/obs-studio-devel-action@v1-beta with: obs: ${{ matrix.obs }} verbose: true qt: ${{ env.qt }} - name: Build plugin run: | OBS_QT_VERSION_MAJOR=${{ steps.obsdeps.outputs.OBS_QT_VERSION_MAJOR }} mkdir build cd build case ${{ matrix.obs }} in 27) cmake_opt=( -D CMAKE_INSTALL_LIBDIR=/usr/lib/ -D CPACK_DEBIAN_PACKAGE_DEPENDS='obs-studio (>= 27), obs-studio (<< 28)' ) ;; 28) cmake_opt=( -D CPACK_DEBIAN_PACKAGE_DEPENDS='obs-studio (>= 28)' ) ;; esac cmake .. \ -D QT_VERSION=$OBS_QT_VERSION_MAJOR \ -D CMAKE_INSTALL_PREFIX=/usr \ -D CMAKE_BUILD_TYPE=RelWithDebInfo \ -D LINUX_PORTABLE=OFF \ -D CPACK_DEBIAN_PACKAGE_SHLIBDEPS=ON \ -D PKG_SUFFIX=-obs${{ matrix.obs }}-${{ matrix.ubuntu }}-x86_64 \ "${cmake_opt[@]}" make -j4 make package echo "FILE_NAME=$(find $PWD -name '*.deb' | head -n 1)" >> $GITHUB_ENV - name: Upload build artifact uses: actions/upload-artifact@v3 with: name: ${{ env.artifactName }} path: '${{ env.FILE_NAME }}' - name: Check package run: | . ci/ci_includes.generated.sh set -ex sudo apt install '${{ env.FILE_NAME }}' case ${{ matrix.obs }} in 27) plugins_dir=/usr/lib/obs-plugins ;; 28) plugins_dir=/usr/lib/x86_64-linux-gnu/obs-plugins ;; esac ldd $plugins_dir/${PLUGIN_NAME}.so > ldd.out if grep not.found ldd.out ; then echo "Error: unresolved shared object." >&2 exit 1 fi ls /usr/share/obs/obs-plugins/${PLUGIN_NAME}/ macos_build: runs-on: macos-12 strategy: fail-fast: false matrix: include: - obs: 27 arch: x86_64 - obs: 28 arch: universal defaults: run: shell: bash steps: - name: Checkout uses: actions/checkout@v3 with: submodules: recursive - name: Setup Environment id: setup run: | set -e echo '::group::Set up code signing' if [[ '${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}' != '' && \ '${{ secrets.MACOS_SIGNING_INSTALLER_IDENTITY }}' != '' && \ '${{ secrets.MACOS_SIGNING_CERT }}' != '' ]]; then echo '::set-output name=haveCodesignIdent::true' else echo '::set-output name=haveCodesignIdent::false' fi if [[ '${{ secrets.MACOS_NOTARIZATION_USERNAME }}' != '' && \ '${{ secrets.MACOS_NOTARIZATION_PASSWORD }}' != '' ]]; then echo '::set-output name=haveNotarizationUser::true' else echo '::set-output name=haveNotarizationUser::false' fi echo '::endgroup::' - name: Install Apple Developer Certificate if: ${{ github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }} uses: apple-actions/import-codesign-certs@253ddeeac23f2bdad1646faac5c8c2832e800071 with: keychain-password: ${{ github.run_id }} p12-file-base64: ${{ secrets.MACOS_SIGNING_CERT }} p12-password: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }} - name: Set Signing Identity if: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }} run: | set -e TEAM_ID=$(echo "${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}" | sed 's/.*(\([A-Za-z0-9]*\))$/\1/') xcrun notarytool store-credentials AC_PASSWORD \ --apple-id "${{ secrets.MACOS_NOTARIZATION_USERNAME }}" \ --team-id "$TEAM_ID" \ --password "${{ secrets.MACOS_NOTARIZATION_PASSWORD }}" - name: Download obs-studio development environment id: obsdeps uses: norihiro/obs-studio-devel-action@v1-beta with: path: /tmp/deps-${{ matrix.obs }}-${{ matrix.arch }} arch: ${{ matrix.arch }} obs: ${{ matrix.obs }} verbose: true qt: ${{ env.qt }} - name: Build plugin run: | arch=${{ matrix.arch }} deps=/tmp/deps-${{ matrix.obs }}-${{ matrix.arch }} MACOSX_DEPLOYMENT_TARGET=${{ steps.obsdeps.outputs.MACOSX_DEPLOYMENT_TARGET }} OBS_QT_VERSION_MAJOR=${{ steps.obsdeps.outputs.OBS_QT_VERSION_MAJOR }} GIT_TAG=$(git describe --tags --always) PKG_SUFFIX=-${GIT_TAG}-obs${{ matrix.obs }}-macos-${{ matrix.arch }} set -e case "${{ matrix.obs }}" in 27) cmake_opt=() ;; 28) cmake_opt=( -D MACOSX_PLUGIN_BUNDLE_TYPE=BNDL -D OBS_BUNDLE_CODESIGN_IDENTITY='${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}' ) ;; esac cmake -S . -B build -G Ninja \ -D QT_VERSION=$OBS_QT_VERSION_MAJOR \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_PREFIX_PATH="$PWD/release/" \ -DCMAKE_OSX_ARCHITECTURES=${arch/#universal/x86_64;arm64} \ -DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \ -DCMAKE_FRAMEWORK_PATH="$deps/Frameworks;$deps/lib/cmake;$deps" \ -D PKG_SUFFIX=$PKG_SUFFIX \ "${cmake_opt[@]}" cmake --build build --config RelWithDebInfo echo "PKG_SUFFIX='$PKG_SUFFIX'" >> ci/ci_includes.generated.sh - name: Prepare package run: | set -ex . ci/ci_includes.generated.sh cmake --install build --config RelWithDebInfo --prefix=release case ${{ matrix.obs }} in 27) (cd release/${PLUGIN_NAME} && ../../ci/macos/change-rpath.sh -obs ${{ matrix.obs }} -lib lib/ bin/${PLUGIN_NAME}.so) cp LICENSE release/${PLUGIN_NAME}/data/LICENSE-$PLUGIN_NAME ;; 28) (cd release/${PLUGIN_NAME}.plugin/Contents && ../../../ci/macos/change-rpath.sh -obs 28 -lib lib/ MacOS/${PLUGIN_NAME}) cp LICENSE release/${PLUGIN_NAME}.plugin/Contents/Resources/LICENSE-$PLUGIN_NAME ;; esac - name: Codesign if: ${{ github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }} run: | . ci/ci_includes.generated.sh set -ex case ${{ matrix.obs }} in 27) files=( $(find release/${PLUGIN_NAME}/ -name '*.dylib') release/${PLUGIN_NAME}/bin/${PLUGIN_NAME}.so ) ;; 28) files=( $(find release/${PLUGIN_NAME}.plugin/ -name '*.dylib') release/${PLUGIN_NAME}.plugin/Contents/MacOS/${PLUGIN_NAME} ) ;; esac for dylib in "${files[@]}"; do codesign --force --sign "${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}" "$dylib" done for dylib in "${files[@]}"; do codesign -vvv --deep --strict "$dylib" done - name: Package run: | . ci/ci_includes.generated.sh set -ex zipfile=$PWD/package/${PLUGIN_NAME}${PKG_SUFFIX}.zip mkdir package case ${{ matrix.obs }} in 27) (cd release/ && zip -r $zipfile ${PLUGIN_NAME}) ;; 28) (cd release/ && zip -r $zipfile ${PLUGIN_NAME}.plugin) ;; esac ci/macos/install-packagesbuild.sh packagesbuild \ --build-folder $PWD/package/ \ build/installer-macOS.generated.pkgproj - name: Productsign if: ${{ github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }} run: | . ci/ci_includes.generated.sh pkgfile=package/${PLUGIN_NAME}${PKG_SUFFIX}.pkg set -e . ci/ci_includes.generated.sh productsign --sign "${{ secrets.MACOS_SIGNING_INSTALLER_IDENTITY }}" $pkgfile package/${PLUGIN_NAME}-signed.pkg mv package/${PLUGIN_NAME}-signed.pkg $pkgfile - name: Notarize if: ${{ startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' && steps.setup.outputs.haveCodesignIdent == 'true' }} uses: norihiro/macos-notarize-action@v1 with: path: package/* keychainProfile: AC_PASSWORD verbose: true - name: Upload build artifact uses: actions/upload-artifact@v3 with: name: ${{ env.artifactName }} path: package/* windows_build: runs-on: windows-2022 strategy: fail-fast: false matrix: obs: [27] arch: [x64] env: visualStudio: 'Visual Studio 17 2022' Configuration: 'RelWithDebInfo' defaults: run: shell: pwsh steps: - name: Checkout uses: actions/checkout@v3 with: submodules: recursive - name: Download obs-studio id: obsdeps uses: norihiro/obs-studio-devel-action@v1-beta with: obs: ${{ matrix.obs }} qt: ${{ env.qt }} - name: Build plugin run: | $CmakeArgs = @( '-G', "${{ env.visualStudio }}" '-DQT_VERSION=${{ steps.obsdeps.outputs.OBS_QT_VERSION_MAJOR }}' '-DCMAKE_SYSTEM_VERSION=10.0.18363.657' "-DCMAKE_INSTALL_PREFIX=$(Resolve-Path -Path "./obs-build-dependencies/plugin-deps-${{ matrix.arch }}")" "-DCMAKE_PREFIX_PATH=$(Resolve-Path -Path "./obs-build-dependencies/plugin-deps-${{ matrix.arch }}")" ) cmake -S . -B build @CmakeArgs cmake --build build --config RelWithDebInfo -j 4 cmake --install build --config RelWithDebInfo --prefix "$(Resolve-Path -Path .)/release" - name: Package plugin run: ci/windows/package-windows.cmd ${{ matrix.obs }} - name: Upload build artifact uses: actions/upload-artifact@v3 with: name: ${{ env.artifactName }} path: package/* obs-command-source-0.4.0/CMakeLists.txt000066400000000000000000000035741440421026000177520ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.12) project(obs-command-source VERSION 0.4.0) set(PLUGIN_AUTHOR "Norihiro Kamae") set(MACOS_BUNDLEID "net.nagater.obs-command-source") set(MACOS_PACKAGE_UUID "DE99133F-7DE7-4A40-BAD9-814A519F32C3") set(MACOS_INSTALLER_UUID "D42A28A8-FCE7-45F4-901B-5F333C2ABC94") set(LINUX_MAINTAINER_EMAIL "norihiro@nagater.net") # NOTE: Also edit ci/plugin.spec for RPM when creating a new plugin. find_package(libobs REQUIRED) find_package(obs-frontend-api REQUIRED) include(cmake/ObsPluginHelpers.cmake) configure_file( plugin-macros.h.in plugin-macros.generated.h ) configure_file( installer/installer-Windows.iss.in ../installer/installer-Windows.generated.iss ) configure_file( ci/ci_includes.sh.in ../ci/ci_includes.generated.sh ) configure_file( ci/ci_includes.cmd.in ../ci/ci_includes.generated.cmd ) set(PLUGIN_SOURCES obs-command-source.c ) add_library(${CMAKE_PROJECT_NAME} MODULE ${PLUGIN_SOURCES}) target_link_libraries(${CMAKE_PROJECT_NAME} OBS::libobs OBS::obs-frontend-api ) target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) if(OS_WINDOWS) # Enable Multicore Builds and disable FH4 (to not depend on VCRUNTIME140_1.DLL when building with VS2019) if (MSVC) add_definitions(/MP /d2FH4-) endif() target_link_libraries(${CMAKE_PROJECT_NAME} OBS::w32-pthreads) endif() if(OS_LINUX) target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -Wall -Wextra) endif() if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -fvisibility=default") set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES PREFIX "") set(MACOSX_PLUGIN_GUI_IDENTIFIER "${MACOS_BUNDLEID}") set(MACOSX_PLUGIN_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION}") set(MACOSX_PLUGIN_SHORT_VERSION_STRING "1") endif() setup_plugin_target(${CMAKE_PROJECT_NAME}) configure_file(installer/installer-macOS.pkgproj.in installer-macOS.generated.pkgproj) obs-command-source-0.4.0/LICENSE000066400000000000000000000431161440421026000162130ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. obs-command-source-0.4.0/README.md000066400000000000000000000042701440421026000164630ustar00rootroot00000000000000Dummy Source to Execute Command =============================== This plugin provides a dummy source to execute arbitrary commands when a scene is switched. ## Current Features * Start a command at the following events. * Show (the source is shown in either preview or program) * Hide (the source is hidden so that no longer shown in neither preview nor program) * Activate (the source goes to the program) * Deactivate (the source goes from the program) * Show in preview (the source goes to the preview) * Hide from preview (the source goes from the preview) * Optionally, kill the created process at these conditions. This feature is not available for Windows as of now. * When hiding, kill the process created at shown. * When deactivating, kill the process created at activated. * When hiding from the preview, kill the process created at preview. ## Possible Usage * Implementing custom tally lights. * Control PTZ cameras by switching the scene. You may combine with CURL to send some commands. * Start and stop a daemon program required for the scene. * Trigger other operations through websocket at the event. A helper script is available at `tools/request-websocket.py`. - Start or stop your streaming and recording. * Not limited to the above. ## Caution Since this plugin executes arbitrary commands, users need to consider security concerns. For example, when combining with `obs-websocket` plugin, a remote user could change property through the websocket interface so that the arbitrary commands can be executed. ## Build ### Linux ``` git clone https://github.com/norihiro/obs-command-source.git cd obs-command-source mkdir build && cd build cmake \ -DLIBOBS_INCLUDE_DIR="" \ -DCMAKE_INSTALL_PREFIX=/usr .. make -j4 sudo make install ``` ### macOS ``` git clone https://github.com/norihiro/obs-command-source.git cd obs-command-source mkdir build && cd build cmake \ -DLIBOBS_INCLUDE_DIR= \ -DLIBOBS_LIB= \ -DOBS_FRONTEND_LIB= \ .. make -j4 # Copy obs-command-source.so to the obs-plugins folder ``` obs-command-source-0.4.0/ci/000077500000000000000000000000001440421026000155745ustar00rootroot00000000000000obs-command-source-0.4.0/ci/ci_includes.cmd.in000066400000000000000000000001161440421026000211450ustar00rootroot00000000000000set PluginName=@CMAKE_PROJECT_NAME@ set PluginVersion=@CMAKE_PROJECT_VERSION@ obs-command-source-0.4.0/ci/ci_includes.sh.in000066400000000000000000000002371440421026000210200ustar00rootroot00000000000000PLUGIN_NAME="@CMAKE_PROJECT_NAME@" PLUGIN_VERSION="@CMAKE_PROJECT_VERSION@" MACOS_BUNDLEID="@MACOS_BUNDLEID@" LINUX_MAINTAINER_EMAIL="@LINUX_MAINTAINER_EMAIL@"obs-command-source-0.4.0/ci/forum-update-info.json000066400000000000000000000001411440421026000220240ustar00rootroot00000000000000{ "plugin_url": "https://obsproject.com/forum/resources/dummy-source-to-execute-command.952/" } obs-command-source-0.4.0/ci/macos/000077500000000000000000000000001440421026000166765ustar00rootroot00000000000000obs-command-source-0.4.0/ci/macos/change-rpath.sh000077500000000000000000000033521440421026000216010ustar00rootroot00000000000000#! /bin/bash libdir='' obsver='' while (($# > 0)); do case "$1" in -lib) libdir="$2" shift 2;; -obs) obsver="$2" shift 2;; *) break ;; esac done set -e function copy_local_dylib { local dylib t=$(mktemp) otool -L $1 > $t awk '/^ \/usr\/local\/(opt|Cellar)\/.*\.dylib/{print $1}' $t | while read -r dylib; do echo "Changing dependency $1 -> $dylib" local b=$(basename $dylib) if test ! -e $libdir/$b; then mkdir -p $libdir cp $dylib $libdir chmod +rwx $libdir/$b install_name_tool -id "@loader_path/$b" $libdir/$b copy_local_dylib $libdir/$b fi install_name_tool -change "$dylib" "@loader_path/../$libdir/$b" $1 done rm -f "$t" } function change_obs27_libs { # obs-frontend-api: # OBS 27.2 provides only `libobs-frontend-api.dylib`. # OBS 28.0 will provide `libobs-frontend-api.1.dylib` and `libobs-frontend-api.dylib`. # libobs: # Both OBS 27.2 and 28.0 provides `libobs.dylib`, `libobs.0.dylib`, `libobs.framework/Versions/A/libobs`. install_name_tool \ -change @rpath/QtWidgets.framework/Versions/5/QtWidgets \ @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets \ -change @rpath/QtGui.framework/Versions/5/QtGui \ @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui \ -change @rpath/QtCore.framework/Versions/5/QtCore \ @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore \ -change @rpath/libobs.framework/Versions/A/libobs \ @rpath/libobs.0.dylib \ -change @rpath/libobs-frontend-api.0.dylib \ @rpath/libobs-frontend-api.dylib \ "$1" } for i in "$@"; do case "$obsver" in 27 | 27.*) change_obs27_libs "$i" ;; 28 | 28.*) : # Not necessary to change dylib paths for OBS 28 ;; esac copy_local_dylib "$i" done obs-command-source-0.4.0/ci/macos/install-packagesbuild.sh000077500000000000000000000011561440421026000235020ustar00rootroot00000000000000#! /bin/bash set -e if which packagesbuild; then exit 0 fi packages_url='http://www.nagater.net/obs-studio/Packages.dmg' packages_hash='6afdd25386295974dad8f078b8f1e41cabebd08e72d970bf92f707c7e48b16c9' for ((retry=5; retry>0; retry--)); do curl -o Packages.dmg $packages_url sha256sum -c <<<"$packages_hash Packages.dmg" && break done hdiutil attach -noverify Packages.dmg packages_volume="$(hdiutil info -plist | grep '/Volumes/Packages' | sed 's/.*\(\/Volumes\/[^<]*\)<\/string>/\1/')" sudo installer -pkg "${packages_volume}/packages/Packages.pkg" -target / hdiutil detach "${packages_volume}" obs-command-source-0.4.0/ci/plugin.spec000066400000000000000000000010721440421026000177460ustar00rootroot00000000000000Name: @PLUGIN_NAME@ Version: @VERSION@ Release: @RELEASE@%{?dist} Summary: Dummy command source plugin for OBS Studio License: GPLv2+ Source0: %{name}-%{version}.tar.bz2 BuildRequires: cmake, gcc, gcc-c++ BuildRequires: obs-studio-devel %description Command source plugin for OBS Studio provides a dummy source that execute arbitrary commands when a scene is switched. %prep %autosetup -p1 %build %{cmake} -DLINUX_PORTABLE=OFF -DLINUX_RPATH=OFF %{cmake_build} %install %{cmake_install} %files %{_libdir}/obs-plugins/%{name}.so %{_datadir}/obs/obs-plugins/%{name}/ obs-command-source-0.4.0/ci/windows/000077500000000000000000000000001440421026000172665ustar00rootroot00000000000000obs-command-source-0.4.0/ci/windows/package-windows.cmd000066400000000000000000000010741440421026000230400ustar00rootroot00000000000000call "%~dp0..\ci_includes.generated.cmd" mkdir package cd package git describe --tags > package-version.txt set /p PackageVersion= DESTINATION $/${OBS_PLUGIN_DESTINATION} COMPONENT obs_rundir EXCLUDE_FROM_ALL) if(OS_WINDOWS) install( FILES $ CONFIGURATIONS "RelWithDebInfo" "Debug" DESTINATION ${OBS_PLUGIN_DESTINATION} COMPONENT ${target}_Runtime OPTIONAL) install( FILES $ CONFIGURATIONS "RelWithDebInfo" "Debug" DESTINATION $/${OBS_PLUGIN_DESTINATION} COMPONENT obs_rundir OPTIONAL EXCLUDE_FROM_ALL) endif() if(MSVC) target_link_options( ${target} PRIVATE "LINKER:/OPT:REF" "$<$>:LINKER\:/SAFESEH\:NO>" "$<$:LINKER\:/INCREMENTAL:NO>" "$<$:LINKER\:/INCREMENTAL:NO>") endif() setup_target_resources(${target} obs-plugins/${target}) if(OS_WINDOWS) add_custom_command( TARGET ${target} POST_BUILD COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_PREFIX=${OBS_OUTPUT_DIR} -DCMAKE_INSTALL_COMPONENT=obs_rundir -DCMAKE_INSTALL_CONFIG_NAME=$ -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake COMMENT "Installing to plugin rundir" VERBATIM) endif() endfunction() function(setup_target_resources target destination) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/data) install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data/ DESTINATION ${OBS_DATA_DESTINATION}/${destination} USE_SOURCE_PERMISSIONS COMPONENT obs_plugins) install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data DESTINATION $/${OBS_DATA_DESTINATION}/${destination} USE_SOURCE_PERMISSIONS COMPONENT obs_rundir EXCLUDE_FROM_ALL) endif() endfunction() endif() obs-command-source-0.4.0/cmake/bundle/000077500000000000000000000000001440421026000175325ustar00rootroot00000000000000obs-command-source-0.4.0/cmake/bundle/macos/000077500000000000000000000000001440421026000206345ustar00rootroot00000000000000obs-command-source-0.4.0/cmake/bundle/macos/Plugin-Info.plist.in000066400000000000000000000015731440421026000244530ustar00rootroot00000000000000 CFBundleName ${MACOSX_PLUGIN_BUNDLE_NAME} CFBundleIdentifier ${MACOSX_PLUGIN_GUI_IDENTIFIER} CFBundleVersion ${MACOSX_PLUGIN_BUNDLE_VERSION} CFBundleShortVersionString ${MACOSX_PLUGIN_SHORT_VERSION_STRING} CFBundleInfoDictionaryVersion 6.0 CFBundleExecutable ${MACOSX_PLUGIN_EXECUTABLE_NAME} CFBundlePackageType ${MACOSX_PLUGIN_BUNDLE_TYPE} CFBundleSupportedPlatforms MacOSX LSMinimumSystemVersion 10.13 obs-command-source-0.4.0/cmake/bundle/macos/entitlements.plist000066400000000000000000000012651440421026000244300ustar00rootroot00000000000000 com.apple.security.cs.allow-unsigned-executable-memory com.apple.security.device.camera com.apple.security.device.audio-input com.apple.security.cs.disable-library-validation com.apple.security.cs.allow-dyld-environment-variables obs-command-source-0.4.0/data/000077500000000000000000000000001440421026000161125ustar00rootroot00000000000000obs-command-source-0.4.0/data/locale/000077500000000000000000000000001440421026000173515ustar00rootroot00000000000000obs-command-source-0.4.0/data/locale/en-US.ini000066400000000000000000000006561440421026000210100ustar00rootroot00000000000000execute-command="Execute Command" shown="Shown" hidden="Hidden" activated="Activated" deactivated="Deactivated" shown-in-preview="Shown in preview" hidden-from-preview="Hidden from preview" prop-sig-show="Send signal to the command at shown when hiding" prop-sig-active="Send signal to the command at activated when deactivating" prop-sig-preview="Send signal to the command at preview when hiding from preview" prop-sig="Signal" obs-command-source-0.4.0/data/locale/ja-JP.ini000066400000000000000000000011171440421026000207530ustar00rootroot00000000000000execute-command="コマンド実行" shown="表示時" hidden="非表示時" activated="アクティブ時" deactivated="非アクティブ時" shown-in-preview="プレビュー時" hidden-from-preview="プレビューからの非表示時" prop-sig-show="非表示時に、表示時コマンドへシグナルを送る" prop-sig-active="非アクティブ時に、アクティブ時に実行したコマンドへシグナルを送る" prop-sig-preview="プレビューからの非表示時に、プレビュー時に実行したコマンドへシグナルを送る" prop-sig="シグナル" obs-command-source-0.4.0/data/locale/pt-BR.ini000066400000000000000000000007231440421026000210000ustar00rootroot00000000000000execute-command="Executar Comando" shown="Exibindo" hidden="Escondido" activated="Ativado" deactivated="Desativado" shown-in-preview="Exibindo na pré-visualização" hidden-from-preview="Escondido da pré-visualização" prop-sig-show="Enviar sinal ao comando em Exibindo quando saindo dela" prop-sig-active="Enviar sinal ao comando em Ativado quando desativando" prop-sig-preview="Enviar sinal ao comando em pré-visualização quando saindo dela" prop-sig="Sinal" obs-command-source-0.4.0/doc/000077500000000000000000000000001440421026000157465ustar00rootroot00000000000000obs-command-source-0.4.0/doc/environments.md000066400000000000000000000011631440421026000210200ustar00rootroot00000000000000# Environment variables This is an experimental feature for Linux and macOS. The behavior might change in furture release. Environment variables are set when calling a process. ### `OBS_CURRENT_SCENE` Name of current scene. In the command for `Activated` and `Deactivated`, the new scene name will be set to this variable. ### `OBS_PREVIEW_SCENE` Name of current scene in preview. ### `OBS_SOURCE_NAME` Name of the command source. It is useful to set visibility of a scene item by combination of `OBS_CURRENT_SCENE` or `OBS_PREVIEW_SCENE`. ### `OBS_TRANSITION_DURATION` Duration in milisecond [ms] for current transition. obs-command-source-0.4.0/installer/000077500000000000000000000000001440421026000171765ustar00rootroot00000000000000obs-command-source-0.4.0/installer/installer-Windows.iss.in000066400000000000000000000044001440421026000237460ustar00rootroot00000000000000#define MyAppName "@CMAKE_PROJECT_NAME@" #define MyAppVersion "@CMAKE_PROJECT_VERSION@" #define MyAppPublisher "@PLUGIN_AUTHOR@" #define MyAppURL "http://www.mywebsite.com" [Setup] ; NOTE: The value of AppId uniquely identifies this application. ; Do not use the same AppId value in installers for other applications. ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) AppId={{CD703FE5-1F2C-4837-BD3D-DD840D83C3E3} AppName={#MyAppName} AppVersion={#MyAppVersion} AppPublisher={#MyAppPublisher} AppPublisherURL={#MyAppURL} AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} DefaultDirName={code:GetDirName} DefaultGroupName={#MyAppName} OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer Compression=lzma SolidCompression=yes [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" [Files] Source: "..\release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "..\LICENSE"; Flags: dontcopy ; NOTE: Don't use "Flags: ignoreversion" on any shared system files [Icons] Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}" Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" [Code] procedure InitializeWizard(); var GPLText: AnsiString; Page: TOutputMsgMemoWizardPage; begin ExtractTemporaryFile('LICENSE'); LoadStringFromFile(ExpandConstant('{tmp}\LICENSE'), GPLText); Page := CreateOutputMsgMemoPage(wpWelcome, 'License Information', 'Please review the license terms before installing {#MyAppName}', 'Press Page Down to see the rest of the agreement. Once you are aware of your rights, click Next to continue.', String(GPLText) ); end; // credit where it's due : // following function come from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45 function GetDirName(Value: string): string; var InstallPath: string; begin // initialize default path, which will be returned when the following registry // key queries fail due to missing keys or for some different reason Result := '{pf}\obs-studio'; // query the first registry value; if this succeeds, return the obtained value if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then Result := InstallPath end; obs-command-source-0.4.0/installer/installer-macOS.pkgproj.in000066400000000000000000000564521440421026000242120ustar00rootroot00000000000000 PACKAGES MUST-CLOSE-APPLICATION-ITEMS MUST-CLOSE-APPLICATIONS PACKAGE_FILES DEFAULT_INSTALL_LOCATION / HIERARCHY CHILDREN CHILDREN GID 80 PATH Applications PATH_TYPE 0 PERMISSIONS 509 TYPE 1 UID 0 CHILDREN CHILDREN CHILDREN CHILDREN BUNDLE_CAN_DOWNGRADE BUNDLE_POSTINSTALL_PATH PATH_TYPE 0 BUNDLE_PREINSTALL_PATH PATH_TYPE 0 CHILDREN GID 80 PATH ../@RELATIVE_INSTALL_PATH@/@CMAKE_PROJECT_NAME@@FIRST_DIR_SUFFIX@ PATH_TYPE 1 PERMISSIONS 493 TYPE 3 UID 0 GID 80 PATH plugins PATH_TYPE 2 PERMISSIONS 509 TYPE 2 UID 0 GID 80 PATH obs-studio PATH_TYPE 2 PERMISSIONS 509 TYPE 2 UID 0 GID 80 PATH Application Support PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Automator PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Documentation PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Extensions PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Filesystems PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Frameworks PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Input Methods PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Internet Plug-Ins PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH LaunchAgents PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH LaunchDaemons PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH PreferencePanes PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Preferences PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 80 PATH Printers PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH PrivilegedHelperTools PATH_TYPE 0 PERMISSIONS 1005 TYPE 1 UID 0 CHILDREN GID 0 PATH QuickLook PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH QuickTime PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Screen Savers PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Scripts PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Services PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Widgets PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH Library PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN CHILDREN GID 0 PATH Shared PATH_TYPE 0 PERMISSIONS 1023 TYPE 1 UID 0 GID 80 PATH Users PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH / PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 PAYLOAD_TYPE 0 PRESERVE_EXTENDED_ATTRIBUTES SHOW_INVISIBLE SPLIT_FORKS TREAT_MISSING_FILES_AS_WARNING VERSION 5 PACKAGE_SCRIPTS POSTINSTALL_PATH PATH_TYPE 0 PREINSTALL_PATH PATH_TYPE 0 RESOURCES PACKAGE_SETTINGS AUTHENTICATION 0 CONCLUSION_ACTION 0 FOLLOW_SYMBOLIC_LINKS IDENTIFIER @MACOS_BUNDLEID@ LOCATION 0 NAME @CMAKE_PROJECT_NAME@ OVERWRITE_PERMISSIONS PAYLOAD_SIZE -1 REFERENCE_PATH RELOCATABLE USE_HFS+_COMPRESSION VERSION @CMAKE_PROJECT_VERSION@ TYPE 0 UUID @MACOS_PACKAGE_UUID@ PROJECT PROJECT_COMMENTS NOTES PROJECT_PRESENTATION BACKGROUND APPAREANCES DARK_AQUA LIGHT_AQUA SHARED_SETTINGS_FOR_ALL_APPAREANCES INSTALLATION TYPE HIERARCHIES INSTALLER LIST CHILDREN DESCRIPTION OPTIONS HIDDEN STATE 1 PACKAGE_UUID @MACOS_PACKAGE_UUID@ TITLE TYPE 0 UUID @MACOS_INSTALLER_UUID@ REMOVED MODE 0 INSTALLATION_STEPS ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewIntroductionController INSTALLER_PLUGIN Introduction LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewReadMeController INSTALLER_PLUGIN ReadMe LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewLicenseController INSTALLER_PLUGIN License LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewDestinationSelectController INSTALLER_PLUGIN TargetSelect LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationTypeController INSTALLER_PLUGIN PackageSelection LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationController INSTALLER_PLUGIN Install LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewSummaryController INSTALLER_PLUGIN Summary LIST_TITLE_KEY InstallerSectionTitle INTRODUCTION LOCALIZATIONS LICENSE LOCALIZATIONS MODE 0 README LOCALIZATIONS SUMMARY LOCALIZATIONS TITLE LOCALIZATIONS PROJECT_REQUIREMENTS LIST BEHAVIOR 3 DICTIONARY IC_REQUIREMENT_OS_DISK_TYPE 1 IC_REQUIREMENT_OS_DISTRIBUTION_TYPE 0 IC_REQUIREMENT_OS_MINIMUM_VERSION 101300 IC_REQUIREMENT_CHECK_TYPE 0 IDENTIFIER fr.whitebox.Packages.requirement.os MESSAGE NAME Operating System STATE RESOURCES ROOT_VOLUME_ONLY PROJECT_SETTINGS ADVANCED_OPTIONS installer-script.domains:enable_currentUserHome 1 BUILD_FORMAT 0 BUILD_PATH PATH ../@RELATIVE_BUILD_PATH@ PATH_TYPE 1 EXCLUDED_FILES PATTERNS_ARRAY REGULAR_EXPRESSION STRING .DS_Store TYPE 0 PROTECTED PROXY_NAME Remove .DS_Store files PROXY_TOOLTIP Remove ".DS_Store" files created by the Finder. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING .pbdevelopment TYPE 0 PROTECTED PROXY_NAME Remove .pbdevelopment files PROXY_TOOLTIP Remove ".pbdevelopment" files created by ProjectBuilder or Xcode. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING CVS TYPE 1 REGULAR_EXPRESSION STRING .cvsignore TYPE 0 REGULAR_EXPRESSION STRING .cvspass TYPE 0 REGULAR_EXPRESSION STRING .svn TYPE 1 REGULAR_EXPRESSION STRING .git TYPE 1 REGULAR_EXPRESSION STRING .gitignore TYPE 0 PROTECTED PROXY_NAME Remove SCM metadata PROXY_TOOLTIP Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING classes.nib TYPE 0 REGULAR_EXPRESSION STRING designable.db TYPE 0 REGULAR_EXPRESSION STRING info.nib TYPE 0 PROTECTED PROXY_NAME Optimize nib files PROXY_TOOLTIP Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING Resources Disabled TYPE 1 PROTECTED PROXY_NAME Remove Resources Disabled folders PROXY_TOOLTIP Remove "Resources Disabled" folders. STATE SEPARATOR NAME @CMAKE_PROJECT_NAME@@PKG_SUFFIX@ PAYLOAD_ONLY TREAT_MISSING_PRESENTATION_DOCUMENTS_AS_WARNING TYPE 0 VERSION 2 obs-command-source-0.4.0/installer/obs-command-source.pkgproj000077500000000000000000000374311440421026000243040ustar00rootroot00000000000000 PACKAGES MUST-CLOSE-APPLICATION-ITEMS MUST-CLOSE-APPLICATIONS PACKAGE_FILES DEFAULT_INSTALL_LOCATION / HIERARCHY CHILDREN CHILDREN GID 80 PATH Applications PATH_TYPE 0 PERMISSIONS 509 TYPE 1 UID 0 CHILDREN CHILDREN CHILDREN CHILDREN CHILDREN CHILDREN CHILDREN GID 80 PATH ../build/obs-command-source.so PATH_TYPE 1 PERMISSIONS 493 TYPE 3 UID 0 GID 80 PATH bin PATH_TYPE 0 PERMISSIONS 493 TYPE 2 UID 0 CHILDREN GID 80 PATH ../data PATH_TYPE 1 PERMISSIONS 493 TYPE 3 UID 0 GID 80 PATH obs-command-source PATH_TYPE 0 PERMISSIONS 493 TYPE 2 UID 0 GID 80 PATH plugins PATH_TYPE 0 PERMISSIONS 493 TYPE 2 UID 0 GID 80 PATH obs-studio PATH_TYPE 0 PERMISSIONS 493 TYPE 2 UID 0 GID 80 PATH Application Support PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH Library PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH / PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 PAYLOAD_TYPE 0 SHOW_INVISIBLE SPLIT_FORKS TREAT_MISSING_FILES_AS_WARNING VERSION 5 PACKAGE_SCRIPTS RESOURCES PACKAGE_SETTINGS AUTHENTICATION 1 CONCLUSION_ACTION 0 FOLLOW_SYMBOLIC_LINKS IDENTIFIER net.nagater.obs-command-source LOCATION 0 NAME obs-command-source plugin OVERWRITE_PERMISSIONS PAYLOAD_SIZE -1 REFERENCE_PATH RELOCATABLE USE_HFS+_COMPRESSION VERSION 4.9.0 TYPE 0 UUID B687A502-5EF9-4574-854F-64FE86F50ED6 PROJECT PROJECT_COMMENTS NOTES PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7 IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250 ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE0MDQuMTMiPgo8c3R5bGUg dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5 Pgo8L2JvZHk+CjwvaHRtbD4K PROJECT_PRESENTATION BACKGROUND APPAREANCES DARK_AQUA LIGHT_AQUA SHARED_SETTINGS_FOR_ALL_APPAREANCES INSTALLATION_STEPS ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewIntroductionController INSTALLER_PLUGIN Introduction LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewReadMeController INSTALLER_PLUGIN ReadMe LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewLicenseController INSTALLER_PLUGIN License LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewDestinationSelectController INSTALLER_PLUGIN TargetSelect LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationTypeController INSTALLER_PLUGIN PackageSelection LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationController INSTALLER_PLUGIN Install LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewSummaryController INSTALLER_PLUGIN Summary LIST_TITLE_KEY InstallerSectionTitle INTRODUCTION LOCALIZATIONS LICENSE LOCALIZATIONS MODE 0 README LOCALIZATIONS SUMMARY LOCALIZATIONS TITLE LOCALIZATIONS LANGUAGE English VALUE obs-command-source PROJECT_REQUIREMENTS LIST BEHAVIOR 3 DICTIONARY IC_REQUIREMENT_CPU_ARCHITECTURE_FAMILY 2 IC_REQUIREMENT_CPU_INTEL_ARCHITECTURE_TYPE 2 IC_REQUIREMENT_CPU_MINIMUM_CPU_CORES_COUNT 1 IC_REQUIREMENT_CPU_MINIMUM_FREQUENCY 866666 IC_REQUIREMENT_CPU_POWERPC_ARCHITECTURE_TYPE 0 IC_REQUIREMENT_CHECK_TYPE 0 IDENTIFIER fr.whitebox.Packages.requirement.cpu MESSAGE LANGUAGE English SECONDARY_VALUE VALUE Your processor is not supported by obs-command-source to function. NAME Processor STATE RESOURCES ROOT_VOLUME_ONLY PROJECT_SETTINGS BUILD_FORMAT 0 BUILD_PATH PATH build PATH_TYPE 1 EXCLUDED_FILES PATTERNS_ARRAY REGULAR_EXPRESSION STRING .DS_Store TYPE 0 PROTECTED PROXY_NAME Remove .DS_Store files PROXY_TOOLTIP Remove ".DS_Store" files created by the Finder. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING .pbdevelopment TYPE 0 PROTECTED PROXY_NAME Remove .pbdevelopment files PROXY_TOOLTIP Remove ".pbdevelopment" files created by ProjectBuilder or Xcode. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING CVS TYPE 1 REGULAR_EXPRESSION STRING .cvsignore TYPE 0 REGULAR_EXPRESSION STRING .cvspass TYPE 0 REGULAR_EXPRESSION STRING .svn TYPE 1 REGULAR_EXPRESSION STRING .git TYPE 1 REGULAR_EXPRESSION STRING .gitignore TYPE 0 PROTECTED PROXY_NAME Remove SCM metadata PROXY_TOOLTIP Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING classes.nib TYPE 0 REGULAR_EXPRESSION STRING designable.db TYPE 0 REGULAR_EXPRESSION STRING info.nib TYPE 0 PROTECTED PROXY_NAME Optimize nib files PROXY_TOOLTIP Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING Resources Disabled TYPE 1 PROTECTED PROXY_NAME Remove Resources Disabled folders PROXY_TOOLTIP Remove "Resources Disabled" folders. STATE SEPARATOR NAME obs-command-source PAYLOAD_ONLY TREAT_MISSING_PRESENTATION_DOCUMENTS_AS_WARNING TYPE 0 VERSION 2 obs-command-source-0.4.0/obs-command-source.c000066400000000000000000000272531440421026000210530ustar00rootroot00000000000000/* * OBS Command Source Plugin * Copyright (C) 2020-2023 Norihiro Kamae * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #ifdef _WIN32 #include #else #include #include #include #include #include #endif #include "plugin-macros.generated.h" struct command_source { char *cmd_show; char *cmd_hide; char *cmd_activate; char *cmd_deactivate; char *cmd_previewed; char *cmd_unpreviewed; #ifndef _WIN32 int sig_show; int sig_activate; int sig_preview; #endif bool is_shown; bool is_preview, was_preview; obs_source_t *self; #ifndef _WIN32 pid_t pid_show; pid_t pid_activate; pid_t pid_preview; DARRAY(pid_t) running_pids; #else // For Windows, just send dummy information to reuse the code for now. // TODO: Implement to hold hProcess and kill it. #define pid_show self #define pid_activate self #define pid_preview self #endif // not _WIN32 }; OBS_DECLARE_MODULE() OBS_MODULE_USE_DEFAULT_LOCALE("obs-command-source", "en-US") #ifndef _WIN32 static void setenv_if(const char *name, const char *val) { if (val) setenv(name, val, 1); } static void setenv_int(const char *name, int val) { char s[16]; snprintf(s, sizeof(s), "%d", val); s[sizeof(s) - 1] = 0; setenv(name, s, 1); } #endif static void fork_exec(const char *cmd, struct command_source *s, #ifndef _WIN32 pid_t *pid_sig #else void *unused #endif ) { #ifdef _WIN32 UNUSED_PARAMETER(unused); PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {sizeof(STARTUPINFO)}; char *p = bstrdup(cmd); CreateProcess(NULL, p, NULL, NULL, FALSE, BELOW_NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); bfree(p); #else obs_source_t *current_src = obs_frontend_get_current_scene(); obs_source_t *preview_src = NULL; if (obs_frontend_preview_program_mode_active()) preview_src = obs_frontend_get_current_preview_scene(); pid_t pid = fork(); if (!pid) { pid_t mypid = getpid(); setpgid(mypid, mypid); setenv_if("OBS_CURRENT_SCENE", obs_source_get_name(current_src)); setenv_if("OBS_PREVIEW_SCENE", obs_source_get_name(preview_src)); setenv_if("OBS_SOURCE_NAME", obs_source_get_name(s->self)); setenv_int("OBS_TRANSITION_DURATION", obs_frontend_get_transition_duration()); execl("/bin/sh", "sh", "-c", cmd, (char *)NULL); _exit(1); } else if (pid != -1) { if (pid_sig) { if (*pid_sig) da_push_back(s->running_pids, pid_sig); *pid_sig = pid; } else da_push_back(s->running_pids, &pid); } obs_source_release(current_src); obs_source_release(preview_src); #endif } static void check_notify_preview(struct command_source *s); static void on_preview_scene_changed(enum obs_frontend_event event, void *param); static void cmdsrc_show(void *data) { struct command_source *s = data; if (s->cmd_show) { fork_exec(s->cmd_show, s, &s->pid_show); } check_notify_preview(s); if (!s->is_shown) obs_frontend_add_event_callback(on_preview_scene_changed, data); s->is_shown = true; } #ifndef _WIN32 static void cmdsrc_kill(const struct command_source *s, pid_t pid, int sig) { blog(LOG_DEBUG, "source '%s' sending signal %d to PGID %d", obs_source_get_name(s->self), sig, pid); killpg(pid, sig); } #endif static void cmdsrc_hide(void *data) { struct command_source *s = data; if (s->cmd_hide) { fork_exec(s->cmd_hide, s, NULL); } #ifndef _WIN32 if (s->pid_show && s->sig_show) cmdsrc_kill(s, s->pid_show, s->sig_show); #endif check_notify_preview(s); if (s->is_shown) obs_frontend_remove_event_callback(on_preview_scene_changed, data); s->is_shown = false; } static void cmdsrc_activate(void *data) { struct command_source *s = data; if (s->cmd_activate) { fork_exec(s->cmd_activate, s, &s->pid_activate); } } static void cmdsrc_deactivate(void *data) { struct command_source *s = data; if (s->cmd_deactivate) { fork_exec(s->cmd_deactivate, s, NULL); } #ifndef _WIN32 if (s->pid_activate && s->sig_activate) cmdsrc_kill(s, s->pid_activate, s->sig_activate); #endif } static inline void cmdsrc_previewed(struct command_source *s) { if (s->cmd_previewed) fork_exec(s->cmd_previewed, s, &s->pid_preview); } static inline void cmdsrc_unpreviewed(struct command_source *s) { if (s->cmd_unpreviewed) fork_exec(s->cmd_unpreviewed, s, NULL); #ifndef _WIN32 if (s->pid_preview && s->sig_preview) cmdsrc_kill(s, s->pid_preview, s->sig_preview); #endif } static void preview_callback(obs_source_t *parent, obs_source_t *child, void *param) { UNUSED_PARAMETER(parent); struct command_source *s = param; if (child == s->self) s->is_preview = true; } static void check_notify_preview(struct command_source *s) { s->is_preview = false; obs_source_t *preview_soure = obs_frontend_get_current_preview_scene(); if (preview_soure) { obs_source_enum_active_sources(preview_soure, preview_callback, s); obs_source_release(preview_soure); } if (s->is_preview && !s->was_preview) cmdsrc_previewed(s); else if (!s->is_preview && s->was_preview) cmdsrc_unpreviewed(s); s->was_preview = s->is_preview; } static void on_preview_scene_changed(enum obs_frontend_event event, void *param) { struct command_source *s = param; switch (event) { case OBS_FRONTEND_EVENT_STUDIO_MODE_ENABLED: case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED: case OBS_FRONTEND_EVENT_STUDIO_MODE_DISABLED: case OBS_FRONTEND_EVENT_SCENE_CHANGED: check_notify_preview(s); break; default: break; } } static const char *command_source_name(void *unused) { UNUSED_PARAMETER(unused); return obs_module_text("execute-command"); } static void command_source_get_defaults(obs_data_t *settings) { #ifndef _WIN32 obs_data_set_default_int(settings, "sig", SIGTERM); #endif } static obs_properties_t *command_source_get_properties(void *unused) { UNUSED_PARAMETER(unused); obs_properties_t *props; #ifndef _WIN32 obs_property_t *prop; #endif props = obs_properties_create(); obs_properties_add_text(props, "cmd_show", obs_module_text("shown"), OBS_TEXT_DEFAULT); obs_properties_add_text(props, "cmd_hide", obs_module_text("hidden"), OBS_TEXT_DEFAULT); obs_properties_add_text(props, "cmd_activate", obs_module_text("activated"), OBS_TEXT_DEFAULT); obs_properties_add_text(props, "cmd_deactivate", obs_module_text("deactivated"), OBS_TEXT_DEFAULT); obs_properties_add_text(props, "cmd_previewed", obs_module_text("shown-in-preview"), OBS_TEXT_DEFAULT); obs_properties_add_text(props, "cmd_unpreviewed", obs_module_text("hidden-from-preview"), OBS_TEXT_DEFAULT); #ifndef _WIN32 obs_properties_add_bool(props, "sigen_show", obs_module_text("prop-sig-show")); obs_properties_add_bool(props, "sigen_activate", obs_module_text("prop-sig-active")); obs_properties_add_bool(props, "sigen_preview", obs_module_text("prop-sig-preview")); prop = obs_properties_add_list(props, "sig", obs_module_text("prop-sig"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_list_add_int(prop, "SIGABRT", SIGABRT); obs_property_list_add_int(prop, "SIGINT", SIGINT); obs_property_list_add_int(prop, "SIGKILL", SIGKILL); obs_property_list_add_int(prop, "SIGTERM", SIGTERM); obs_property_list_add_int(prop, "SIGHUP", SIGHUP); obs_property_list_add_int(prop, "SIGUSR1", SIGUSR1); obs_property_list_add_int(prop, "SIGUSR2", SIGUSR2); #endif return props; } static void command_source_destroy(void *data) { struct command_source *s = data; if (s->is_shown) obs_frontend_remove_event_callback(on_preview_scene_changed, data); if (s->cmd_show) bfree(s->cmd_show); if (s->cmd_hide) bfree(s->cmd_hide); if (s->cmd_activate) bfree(s->cmd_activate); if (s->cmd_deactivate) bfree(s->cmd_deactivate); if (s->cmd_previewed) bfree(s->cmd_previewed); if (s->cmd_unpreviewed) bfree(s->cmd_unpreviewed); #ifndef _WIN32 da_free(s->running_pids); #endif // not _WIN32 bfree(s); } static inline char *bstrdup_nonzero(const char *s) { if (!*s) return NULL; return bstrdup(s); } static void command_source_update(void *data, obs_data_t *settings) { struct command_source *s = data; if (s->cmd_show) bfree(s->cmd_show); if (s->cmd_hide) bfree(s->cmd_hide); if (s->cmd_activate) bfree(s->cmd_activate); if (s->cmd_deactivate) bfree(s->cmd_deactivate); if (s->cmd_previewed) bfree(s->cmd_previewed); if (s->cmd_unpreviewed) bfree(s->cmd_unpreviewed); s->cmd_show = bstrdup_nonzero(obs_data_get_string(settings, "cmd_show")); s->cmd_hide = bstrdup_nonzero(obs_data_get_string(settings, "cmd_hide")); s->cmd_activate = bstrdup_nonzero(obs_data_get_string(settings, "cmd_activate")); s->cmd_deactivate = bstrdup_nonzero(obs_data_get_string(settings, "cmd_deactivate")); s->cmd_previewed = bstrdup_nonzero(obs_data_get_string(settings, "cmd_previewed")); s->cmd_unpreviewed = bstrdup_nonzero(obs_data_get_string(settings, "cmd_unpreviewed")); #ifndef _WIN32 int sig = obs_data_get_int(settings, "sig"); s->sig_show = obs_data_get_bool(settings, "sigen_show") ? sig : 0; s->sig_activate = obs_data_get_bool(settings, "sigen_activate") ? sig : 0; s->sig_preview = obs_data_get_bool(settings, "sigen_preview") ? sig : 0; #endif } static void *command_source_create(obs_data_t *settings, obs_source_t *source) { struct command_source *s = bzalloc(sizeof(struct command_source)); s->self = source; #ifndef _WIN32 da_init(s->running_pids); #endif // not _WIN32 command_source_update(s, settings); return s; } #ifndef _WIN32 static bool cmdsrc_waitpid(struct command_source *s, pid_t pid) { int wstatus = 0; pid_t ret = waitpid(pid, &wstatus, WNOHANG); if (ret == pid) { char st[32] = {0}; if (WIFSIGNALED(wstatus)) snprintf(st, sizeof(st) - 1, " by signal %d", WTERMSIG(wstatus)); else if (WCOREDUMP(wstatus)) snprintf(st, sizeof(st) - 1, " with core dump"); else if (WIFEXITED(wstatus)) snprintf(st, sizeof(st) - 1, " with status %d", WEXITSTATUS(wstatus)); blog(LOG_DEBUG, "source '%s': PID %d exited%s", obs_source_get_name(s->self), pid, st); return true; } return false; } static void cmdsrc_tick(void *data, float seconds) { UNUSED_PARAMETER(seconds); struct command_source *s = data; if (s->pid_show) { if (cmdsrc_waitpid(s, s->pid_show)) s->pid_show = 0; } if (s->pid_activate) { if (cmdsrc_waitpid(s, s->pid_activate)) s->pid_activate = 0; } if (s->pid_preview) { if (cmdsrc_waitpid(s, s->pid_preview)) s->pid_preview = 0; } for (size_t i = 0; i < s->running_pids.num; i++) { if (cmdsrc_waitpid(s, s->running_pids.array[i])) { da_erase(s->running_pids, i); i--; } } } #endif // not _WIN32 static struct obs_source_info command_source_info = { .id = "command_source", .type = OBS_SOURCE_TYPE_INPUT, .get_name = command_source_name, .create = command_source_create, .destroy = command_source_destroy, .update = command_source_update, .show = cmdsrc_show, .hide = cmdsrc_hide, .activate = cmdsrc_activate, .deactivate = cmdsrc_deactivate, .get_defaults = command_source_get_defaults, .get_properties = command_source_get_properties, #ifndef _WIN32 .video_tick = cmdsrc_tick, #endif // not _WIN32 }; bool obs_module_load() { obs_register_source(&command_source_info); return true; } obs-command-source-0.4.0/plugin-macros.h.in000066400000000000000000000017541440421026000205460ustar00rootroot00000000000000/* * OBS Command Source Plugin * Copyright (C) 2020-2023 Norihiro Kamae * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PLUGIN_MACROS_H #define PLUGIN_MACROS_H #define PLUGIN_NAME "@CMAKE_PROJECT_NAME@" #define PLUGIN_VERSION "@CMAKE_PROJECT_VERSION@" #define blog(level, msg, ...) blog(level, "[" PLUGIN_NAME "] " msg, ##__VA_ARGS__) #endif // PLUGIN_MACROS_H obs-command-source-0.4.0/tools/000077500000000000000000000000001440421026000163415ustar00rootroot00000000000000obs-command-source-0.4.0/tools/request-websocket.py000077500000000000000000000040651440421026000223770ustar00rootroot00000000000000#! /usr/bin/python3 import asyncio import json loop = asyncio.get_event_loop() async def connect_and_send(rr): # NOTE: User has to edit host, port, and password. try: import simpleobsws except ModuleNotFoundError: import sys sys.stderr.write('Error: This script requires a module simpleobsws (https://github.com/IRLToolkit/simpleobsws).\n') sys.exit(1) try: import os obsws_port = int(os.environ['OBSWS_PORT']) except: obsws_port = 4444 ws = simpleobsws.obsws(host='127.0.0.1', port=obsws_port, password=None, loop=loop) await ws.connect() for req, data in rr: print('req="%s" data=%s'%(str(req), str(data))) if req=='sleep': await asyncio.sleep(data) else: res = await ws.call(req, data) print(json.dumps(res, indent="\t")) await ws.disconnect() help_str='''NAME request-websocket.py - a helper command to send requests to OBS Studio SYNOPSIS request-websocket.py [request_type data] ... request-websocket.py --help DESCRIPTION This script will take pairs of request_type and data and send each pair to OBS Studio. The last pair can skip data if you don't need to send any data. request_type This is a request-type supported by obs-websocket protocol or 'sleep'. If request_type is 'sleep', data has to be a non-negative number to sleep in seconds. Otherwise, the request-type will be directly send to obs-websocket. data The data is a JSON text. The data can be an empty string if you don't need to send any data. EXAMPLES request-websocket.py GetVersion request-websocket.py SetPreviewScene '{"scene-name": "Scene"}' request-websocket.py SetCurrentScene '{"scene-name": "Scene1"}' sleep 10 SetCurrentScene '{"scene-name": "Scene2"}' ''' def main(): import sys req = None rr = list() st = 0 for a in sys.argv[1:]: if a=='--help': print(help_str) return 0 if st==0: req = a st = 1 elif st==1: if len(a): data = json.loads(a) else: data = None rr.append((req, data)) st = 0 if st==1: rr.append((req, None)) loop.run_until_complete(connect_and_send(rr)) if __name__ == '__main__': main()