diff --git a/.gitmodules b/.gitmodules
index cb9da41..f0d468b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,13 +1,15 @@
[submodule "plugins/win-dshow/libdshowcapture"]
path = plugins/win-dshow/libdshowcapture
url = https://github.com/jp9000/libdshowcapture.git
-
[submodule "plugins/mac-syphon/syphon-framework"]
path = plugins/mac-syphon/syphon-framework
url = https://github.com/palana/Syphon-Framework.git
[submodule "plugins/enc-amf"]
path = plugins/enc-amf
- url = https://github.com/Xaymar/OBS-AMD-Advanced-Media-Framework.git
+ url = https://github.com/Xaymar/obs-studio_amf-encoder-plugin.git
[submodule "plugins/obs-browser"]
path = plugins/obs-browser
url = https://github.com/kc5nra/obs-browser.git
+[submodule "plugins/obs-vst"]
+ path = plugins/obs-vst
+ url = https://github.com/DDRBoxman/obs-vst.git
diff --git a/.mailmap b/.mailmap
index 754acfd..46fd23e 100644
--- a/.mailmap
+++ b/.mailmap
@@ -3,3 +3,6 @@ Zachary Lund
Benjamin Klettbach
BtbN
John Bradley
+HomeWorld hwdro
+Michael Fabian Dirks
+Martell Malone
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..00376f9
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,52 @@
+language: cpp
+
+env:
+ global:
+ # AWS S3 creds
+ # access key
+ - secure: "MfhOg+84yb4ZHB2tM8PIPFQX2Y+WLN0I0iiAgyLC4KaHPUoNOyloe9yk6OjV7Lj7SZWqTlQUsqHa8S9mOUswGIody1Ydglo4RvyGOKCd8I6b2ri/jE8qHVuD9sO+sNlIxq4YqqG/qReTsbSs2YEgLneZUCYLCk/fihl8L6eVuSc="
+ # secret
+ - secure: "JRQVU2zgC3hY6CEY+Crmh/upp93En0BzKaLcsuBT538johNlK7m5hn3m2UOw63seLvBvVaKKWUDj9N986a3DwcXxWPMyF/9ctXgNWy39WzaVWxrbVR5nQB1fdiRp5YEgkoVN+gEm3OVF7sV5AGzh5/8CvEdRCoTLIGgMGHxW9mc="
+
+matrix:
+ include:
+ - os: osx
+ env:
+ - CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
+ - CEF_BUILD_VERSION=3.2987.1588.g1952835
+ before_install: "./CI/install-dependencies-osx.sh"
+ before_script: "./CI/before-script-osx.sh"
+ before_deploy: "./CI/before-deploy-osx.sh"
+
+ - os: linux
+ dist: trusty
+ sudo: required
+ before_install: "./CI/install-dependencies-linux.sh"
+ before_script: "./CI/before-script-linux.sh"
+
+script: cd ./build && make -j4 && cd -
+
+deploy:
+ provider: s3
+ access_key_id: $AWS_ACCESS_KEY
+ secret_access_key: $AWS_SECRET_KEY
+ skip_cleanup: true
+ local_dir: nightly
+ bucket: obs-nightly
+ region: us-west-2
+ acl: public_read
+ on:
+ repo: jp9000/obs-studio
+ condition: "$TRAVIS_OS_NAME = osx"
+ all_branches: true
+
+# The channel name "azubu.il.us.quakenet.org#obs-dev" is encrypted against jp9000/obs-studio to prevent IRC spam of forks
+notifications:
+ irc:
+ skip_join: false
+ template:
+ - "[Travis CI|%{result}] %{repository_name}/%{branch} (%{author} - %{commit_subject}) %{build_url}"
+ channels:
+ - secure: k9j7+ogVODMlveZdd5pP73AVLCFl1VbzVaVon0ECn3EQcxnLSpiZbc6l+PnIUKgee5pRKtUB4breufgmr4puq3s69YeQiOVKk5gx2yJGZ5jGacbSne0xTspzPxapiEbVUkcJ2L7gKntDG4+SUiW67dtt4G26O7zsErDF/lY/woQ=
+ on_failure: always
+ on_success: change
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..5ca5194
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,477 @@
+Contributors are sorted by their amount of commits / translated strings.
+
+Contributors:
+Jim
+Palana
+fryshorts
+BtbN
+John Bradley
+Gol-D-Ace
+Colin Edwards
+Richard Stanway
+Zachary Lund
+Michael Fabian Dirks
+Martell Malone
+Christoph Hohmann
+HomeWorld
+cg2121
+dodgepong
+derrod
+Ryan Foster
+Radzaquiel
+Socapex
+Skyler Lipthay
+SuslikV
+Arkkis
+Cephas Reis
+GoaLitiuM
+Danni
+Jess Mayo
+Kris Moore
+Carl Fürstenberg
+juvester
+Anry
+CoDEmanX
+Ján Mlynek
+Manuel Kroeber
+sorayuki
+Alexandre Vicenzi
+Benjamin Klettbach
+bl
+Bl00drav3n
+Blackhive
+Charles Ray Shisler III
+Jeremiah Senkpiel
+John R. Bradley
+Kilian von Pflugk
+Serge Paquet
+shiina424
+shousa
+Timo Gurr
+adray
+Andrei Nistor
+Andrew Surzhynskyi
+Azat Khasanshin
+Ben Torell
+bootkiller
+Brian S. Stephan
+Eric Bataille
+Joseph El-Khouri
+jpk
+Kurt Kartaltepe
+Lexsus
+Lionheart Zhang
+paibox
+Robin Hielscher
+skwerlman
+taesheren
+Take Vos
+Taylor Blau
+Warren Turkal
+yogpstop
+Aarni Koskela
+Aesen Vismea
+Akagi201
+Alexander Uhlmann
+Alexandre Biny
+Andreas Reischuck
+Anthony Catel
+Anthony Super
+Asgeir Mortensen
+Autumin
+Aydin Akan
+Bernd Buschinski
+bla
+boombatower
+Caitlin Potter
+Caleb Anderson
+CallumHoward
+Cam
+CommanderRoot
+Copy Liu
+cryptonaut
+Dan Dascalescu
+David Cooper
+David McMackins II
+dennis
+Derrick Lambert
+Emil Sayahi
+EpicCoder
+Ethan Lee
+Frank Gehann
+Giorgio Pellero
+Grigorii Chirkov
+Guillermo A. Amaral
+Gökberk Yaltıraklı
+Haden F
+Iblis Lin
+Jake Probst
+Jamy Timmermans
+Jimmy Berry
+Jkoan
+Joel Bethke
+Julian Miller
+Kazuki Oishi
+ka’imi
+Kevin
+Kevin Tardif
+Lasse Dalegaard
+lemmi
+Lioncash
+Lucian Poston
+Lukas Monka
+Luke Yelavich
+mape
+Marc Chambers
+Mark Vaughn
+Mathias Panzenböck
+Matthew McNamara
+MedicMomcilo
+michael bishop
+Michael Hoang
+Momcilo Medic
+nd
+Nicolas F
+Night
+Olle Kelderman
+pantonvich
+partouf
+Peter SZTANOJEV
+pipll
+raincomplex
+repeat
+Ricardo Constantino
+Rodrigo Ipince
+rpslack
+Ryan Sullivan
+sam8641
+Seth Murphy
+Seung-Woo Kim
+Simon
+Teemu Kauhanen
+thekrzos
+Thomas McGrew
+TotalCaesar659
+vic
+vividnightmare
+VodBox
+wayne wang
+Weikardzaena
+Will Jamieson
+William Casarin
+Younes SERRAJ
+Ziemas
+
+Translations:
+Arabic
+ Abdullah AL-Qahtani (Za7ef_SA)
+ majdcomp
+ ZILZAL
+ BWU Wheelman (Wheelman)
+ Saleh Luxmaroc (salehoukiki)
+ Gol D. Ace (goldace)
+ معتصم دعنا (rozana-media)
+ chaironeko
+ dodgepong
+ FC Barcelona HD (kurdnews)
+Basque
+ Alexander Gabilondo (alexgabi)
+ Xabier Aramendi (azpidatziak)
+ Osoitz
+ txaro
+ etxondoko
+ Gol D. Ace (goldace)
+ dodgepong
+Bulgarian
+ kalmarin
+ Seyhan Halil (yildirim17)
+ Viktor Kitov (viktorkitov)
+ Stanislav_Evtimov
+ Ivan (SKDown)
+Catalan
+ Jaime Muñoz Martín (jmmartin_5)
+ jmontane
+ Nil Campamà (Soifam)
+ Aleix Vidal i Gaya (leixet)
+ Gol D. Ace (goldace)
+Chinese Simplified
+ Bob Liu (Akagi201)
+ PabloLiu (719018105)
+ Sasasu
+ cai_miao
+ David Kuo (s50407s)
+ Boyuan Yang (073plan)
+ 鲜童 (xiananjyzy)
+ copyliu
+ wwj402_github
+ Bing Feng (fengbing123)
+ dodgepong
+ WaterOtaku
+Chinese Traditional
+ TzeKei Lee (chikei)
+ dodgepong
+ Julian_Lai
+ Chien-Yu Lin (u900011)
+ David Kuo (s50407s)
+ You-Ruei Tzeng (e222et)
+ Inndy.Lin (inndy)
+ Meng Hao Li (GazCore)
+ Gol D. Ace (goldace)
+ Watson Tsai (ashaneba)
+ cai_miao
+ Jimmy Huang (f56112000)
+ chaironeko
+ tomoe-musashi
+Croatian
+ medicmomcilo
+ Gol D. Ace (goldace)
+ dodgepong
+Czech
+ Jirka 'Venty' Michel (VentyCZ)
+ Sawanyo
+ dodgepong
+ Kiznoh
+Danish
+ Jens Hyllegaard (Hyllegaard)
+ Anders G. Jørgensen (spirit55555)
+ MaltahlGaming (maltahlgaming)
+ NCAA
+ Anders Urban (minikaliffen)
+ Christian Henriksen (cnhenriksen)
+ Gol D. Ace (goldace)
+ Johan Keller Jensen (JKeller)
+Dutch
+ Eric Bataille (ThoNohT)
+ Michel Snippe (michelsnippe)
+ Nicole (NIsengo)
+ Jasper J (JassieJ)
+ Gol D. Ace (goldace)
+ JorRy
+Estonian
+ MartinEwing
+ AndresTraks
+Finnish
+ ArkkisN (j)
+ dodgepong
+ Jarska
+ Jarppi (Jarppi01)
+ Gol D. Ace (goldace)
+ chaironeko
+French
+ radzaquiel
+ Yberion
+ Nunzio Conte (nunzioconte54)
+ Stéphane Lepin (Palakis)
+ Léo (leeo97one)
+ DoK_-
+ BoboopTeam
+ DarkInFire
+ steve_fr
+ Grisou2907
+ McGuygnol
+ Gabriel Dugny (Gabigabigo)
+ Gol D. Ace (goldace)
+ dodgepong
+ chaironeko
+Galician
+ Xesús M. Mosquera Carregal (xesusmosquera)
+ Gol D. Ace (goldace)
+ chaironeko
+German
+ Gol D. Ace (goldace)
+ Michael Fabian Dirks (Xaymar)
+ dodgepong
+ Benjamin Klettbach (benklett)
+ Sven Kirschbaum (fallobst22) (fallobst22)
+ random31415
+ Palana
+ Dennis Giebert (Isegrim) (isegrimderwolf)
+ Jonathan (macburgerjunior)
+ Robin Hielscher (Jack0r)
+ BoJustus
+ Jonas Otto (jottosmail)
+ mdod
+ Prince_of_Raop
+ Tiim
+ Tim (robske_110) (robske110)
+ WurstOnAir
+Greek
+ Mepharees
+ Tasos Sahanidis (tatokis)
+ Alex Kalles (alexakis1997)
+ iosifidis
+ chaironeko
+ dodgepong
+Hebrew
+ amirsher
+ Chemi
+ epic_ziver_D
+Hungarian
+ Gige
+ Adam Liszkai (adamos42)
+ dodgepong
+ Gol D. Ace (goldace)
+Italian
+ LordShadow95
+ Marocco2
+ dodgepong
+ Edoardo Macrì (edomacri)
+ smart2128
+ Edoardo “OfficialDJMela” Macrì (agersforum)
+ ScemEnzo
+ Fisherozzo
+ Gol D. Ace (goldace)
+ Sergio Beneduce (sbeneduce)
+ SkyLion
+Japanese
+ shousa
+ Kenta (kenta0644)
+ dodgepong
+ chaironeko
+Korean
+ Wonjoo Noh (ynetwork)
+ Gol D. Ace (goldace)
+ antome
+Lithuanian
+ Justas Vilimas (tyntas)
+Malay
+ amsyar ZeRo (amsyarminer555)
+ dodgepong
+Norwegian Bokmal
+ Taesh (magnusmbratteng)
+ dodgepong
+ mgKaiztra
+ Tommy (nwgat)
+ Oddbjørn Grytdal (Fooshi)
+ Decicus
+ Gol D. Ace (goldace)
+ areedw
+ Legend27
+ chaironeko
+ Mats Andreassen (MatsA)
+Pirate English
+ Matthew Hatcher (MatthewSH)
+ jkcoaster
+ Charlie W. (wallichc)
+ iltrof
+ chaironeko
+ Gol D. Ace (goldace)
+Polish
+ grocal
+ Michał Durak (micechal)
+ Damian Korcz (damikiller)
+ opl
+ Gol D. Ace (goldace)
+ dodgepong
+ Mateusz (Silesianek)
+ Michał Lewczak (michal200507)
+Portuguese
+ André Biscaia (LazP)
+ dodgepong
+ joaoboia
+ Gol D. Ace (goldace)
+Portuguese, Brazilian
+ Ramon Mendes (rbrgameplays)
+ Fabio Madia (Shaolin)
+ Burkes
+ TFSThiagoBR98
+ CaioWzy
+ clr0dr1g
+ aalonsomb
+ André Gama (ToeOficial)
+ Gol D. Ace (goldace)
+ dodgepong
+ ThisGuy
+Romanian
+ Cristian Silaghi (stelistcristi)
+ banrek
+ Hisashi
+ Gol D. Ace (goldace)
+ chaironeko
+ dodgepong
+Russian
+ iltrof
+ Alek Nirov (dectanova)
+ VNGXR
+ dodgepong
+ Pavel (Shevalie)
+ Maxim Gribanov (MaximGribanov)
+ Andy (anry025)
+ fromgate
+ Gol D. Ace (goldace)
+ Andrei Stepanov (adem4ik)
+ Vlad (KoTmaxHo)
+ Bugo
+ Mixaill
+ Sergei Fug1t1v3 (fug)
+ Walt Gee (vovanych)
+ Sigge Stjärnholm (Kladdy)
+ Yuri Mihaqlov (yurijmi)
+Serbian (Cyrillic)
+ medicmomcilo
+ Gol D. Ace (goldace)
+Serbian (Latin)
+ medicmomcilo
+ Gol D. Ace (goldace)
+ dodgepong
+Slovak
+ Ján M (longmoped)
+ Anton Lokaj (anlo)
+ LoLLy Nka (lollynka279)
+Slovenian
+ kristjan.krusic (krusic22)
+ ArcaneWater
+ Gol D. Ace (goldace)
+ dodgepong
+Spanish
+ Roberto Lorenzo (HonzoNebro)
+ Marcos Vidal Martinez (M4RK22)
+ Jaime Martinez Rincon (mrjaime1999)
+ Jaime Muñoz Martín (jmmartin_5)
+ Maximiliano Schtroumpftech Pena-Roig (som2tokmynam)
+ Eleazar Córcoles (MtrElee3)
+ Gol D. Ace (goldace)
+ Sigge Stjärnholm (Kladdy)
+ chaironeko
+ dodgepong
+ Rodrigo Ipince (ipince)
+ Rubén Pérez (RixzZ)
+Swedish
+ Anton R (FirePhoenix)
+ Sigge Stjärnholm (Kladdy)
+ Laccy IEST (Laccy)
+ Olle Dahström (odahlstrom)
+ Gustav Ekner (ekner)
+ Gol D. Ace (goldace)
+ Henrik Mattsson-Mårn (rchk)
+ chaironeko
+ Jonas Svensson (jonassanojj99)
+Tamil
+ Kolappan Nathan (kolappannathan)
+Thai
+ sakuhanachan* (sakuhanachanloli)
+ 盛凤阁 (execzero)
+ nongnoobjung (kitcharuk_4)
+ dodgepong
+Turkish
+ Ali Kömesöğütlü (Mobile46) (byzlo685)
+ omer.karagoz (mrkaragoz)
+ monolifed
+ Cemal Dursun (cmldrs)
+ Savas Tokmak (Laserist)
+ Murat Karagöz (anemon_1994)
+ gecebekcisi1
+ Gol D. Ace (goldace)
+ Hydroboost
+ mustafaa
+Ukrainian
+ SuslikV
+ Юрій (Devinit)
+ Andy (anry025)
+ Maksym Tymoshyk (maximillian_)
+Vietnamese
+ Johnny “max20091” Utah (boostyourprogram)
+ Hưng Nguyễn (hoyostudio)
+ Hà Phi Hùng (haphihungcom)
+ dodgepong
+ NCAA
diff --git a/CI/before-deploy-osx.sh b/CI/before-deploy-osx.sh
new file mode 100755
index 0000000..f427b36
--- /dev/null
+++ b/CI/before-deploy-osx.sh
@@ -0,0 +1,56 @@
+hr() {
+ echo "───────────────────────────────────────────────────"
+ echo $1
+ echo "───────────────────────────────────────────────────"
+}
+
+# Exit if something fails
+set -e
+
+# Generate file name variables
+export GIT_HASH=$(git rev-parse --short HEAD)
+export FILE_DATE=$(date +%Y-%m-%d.%H:%M:%S)
+export FILENAME=$FILE_DATE-$GIT_HASH-$TRAVIS_BRANCH-osx.pkg
+
+cd ./build
+
+# Move the CEF plugin out before running build_app so that it doesn't get packaged twice
+hr "Moving CEF out to preserve linking"
+mv ./rundir/RelWithDebInfo/obs-plugins/CEF.app ./
+mv ./rundir/RelWithDebInfo/obs-plugins/obs-browser.so ./
+
+# Package everything into a nice .app
+hr "Packaging .app"
+STABLE=false
+if [ -n "${TRAVIS_TAG}" ]; then
+ STABLE=true
+fi
+
+sudo python ../CI/install/osx/build_app.py --public-key ../CI/install/osx/OBSPublicDSAKey.pem --sparkle-framework ../../sparkle/Sparkle.framework --base-url "https://obsproject.com/osx_update" --stable=$STABLE
+
+# Move the CEF plugin back to where it belongs
+hr "Moving CEF back"
+mv ./CEF.app ./rundir/RelWithDebInfo/obs-plugins/
+mv ./obs-browser.so ./rundir/RelWithDebInfo/obs-plugins/
+
+# Package app
+hr "Generating .pkg"
+packagesbuild ../CI/install/osx/CMakeLists.pkgproj
+
+# Signing stuff
+hr "Decrypting Cert"
+openssl aes-256-cbc -K $encrypted_dd3c7f5e9db9_key -iv $encrypted_dd3c7f5e9db9_iv -in ../CI/osxcert/Certificates.p12.enc -out Certificates.p12 -d
+hr "Creating Keychain"
+security create-keychain -p mysecretpassword build.keychain
+security default-keychain -s build.keychain
+security unlock-keychain -p mysecretpassword build.keychain
+security set-keychain-settings -t 3600 -u build.keychain
+hr "Importing certs into keychain"
+security import ./Certificates.p12 -k build.keychain -T /usr/bin/productsign -P ""
+hr "Signing Package"
+productsign --sign 'Developer ID Installer: Hugh Bailey (2MMRE5MTB8)' ./OBS.pkg ./$FILENAME
+
+# Move to the folder that travis uses to upload artifacts from
+hr "Moving package to nightly folder for distribution"
+mkdir ../nightly
+sudo mv ./$FILENAME ../nightly
diff --git a/CI/before-deploy-win.cmd b/CI/before-deploy-win.cmd
new file mode 100644
index 0000000..2be9c5f
--- /dev/null
+++ b/CI/before-deploy-win.cmd
@@ -0,0 +1,3 @@
+xcopy /e C:\projects\obs-studio\build32\rundir\RelWithDebInfo C:\projects\obs-studio\build\
+robocopy C:\projects\obs-studio\build64\rundir\RelWithDebInfo C:\projects\obs-studio\build\ /E /XC /XN /XO
+7z a build.zip C:\projects\obs-studio\build\*
\ No newline at end of file
diff --git a/CI/before-script-linux.sh b/CI/before-script-linux.sh
new file mode 100755
index 0000000..7a42daa
--- /dev/null
+++ b/CI/before-script-linux.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -ex
+
+mkdir build && cd build
+cmake ..
diff --git a/CI/before-script-osx.sh b/CI/before-script-osx.sh
new file mode 100755
index 0000000..922816b
--- /dev/null
+++ b/CI/before-script-osx.sh
@@ -0,0 +1,3 @@
+mkdir build
+cd build
+cmake -DENABLE_SPARKLE_UPDATER=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 -DDepsPath=/tmp/obsdeps -DVLCPath=$PWD/../../vlc-master -DBUILD_BROWSER=ON -DCEF_ROOT_DIR=$PWD/../../cef_binary_${CEF_BUILD_VERSION}_macosx64 ..
diff --git a/CI/install-dependencies-linux.sh b/CI/install-dependencies-linux.sh
new file mode 100755
index 0000000..134756b
--- /dev/null
+++ b/CI/install-dependencies-linux.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+set -ex
+
+sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next -y
+sudo apt-get -qq update
+sudo apt-get install -y \
+ build-essential \
+ checkinstall \
+ cmake \
+ libasound2-dev \
+ libavcodec-ffmpeg-dev \
+ libavdevice-ffmpeg-dev \
+ libavfilter-ffmpeg-dev \
+ libavformat-ffmpeg-dev \
+ libavutil-ffmpeg-dev \
+ libcurl4-openssl-dev \
+ libfontconfig-dev \
+ libfreetype6-dev \
+ libgl1-mesa-dev \
+ libjack-jackd2-dev \
+ libjansson-dev \
+ libpulse-dev \
+ libqt5x11extras5-dev \
+ libspeexdsp-dev \
+ libswresample-ffmpeg-dev \
+ libswscale-ffmpeg-dev \
+ libudev-dev \
+ libv4l-dev \
+ libvlc-dev \
+ libx11-dev \
+ libx264-dev \
+ libxcb-shm0-dev \
+ libxcb-xinerama0-dev \
+ libxcomposite-dev \
+ libxinerama-dev \
+ pkg-config \
+ qtbase5-dev
diff --git a/CI/install-dependencies-osx.sh b/CI/install-dependencies-osx.sh
new file mode 100755
index 0000000..69c71e9
--- /dev/null
+++ b/CI/install-dependencies-osx.sh
@@ -0,0 +1,42 @@
+# Exit if something fails
+set -e
+
+git fetch --tags
+
+# Leave obs-studio folder
+cd ../
+
+# Install Packages app so we can build a package later
+# http://s.sudre.free.fr/Software/Packages/about.html
+curl -L -O https://s3-us-west-2.amazonaws.com/obs-nightly/Packages.pkg -f --retry 5 -C -
+sudo installer -pkg ./Packages.pkg -target /
+
+brew update
+
+#Base OBS Deps
+brew install qt5 jack speexdsp
+
+# Fetch and untar prebuilt OBS deps that are compatible with older versions of OSX
+curl -L -O https://s3-us-west-2.amazonaws.com/obs-nightly/osx-deps.tar.gz -f --retry 5 -C -
+tar -xf ./osx-deps.tar.gz -C /tmp
+
+# Fetch vlc codebase
+curl -L -o vlc-master.zip https://github.com/videolan/vlc/archive/master.zip -f --retry 5 -C -
+unzip -q ./vlc-master.zip
+
+# Get sparkle
+curl -L -o ./sparkle.tar.bz2 https://github.com/sparkle-project/Sparkle/releases/download/1.16.0/Sparkle-1.16.0.tar.bz2
+mkdir ./sparkle
+tar -xf ./sparkle.tar.bz2 -C ./sparkle
+sudo cp -R ./sparkle/Sparkle.framework /Library/Frameworks/Sparkle.framework
+
+# CEF Stuff
+curl -kLO https://obs-nightly.s3-us-west-2.amazonaws.com/cef_binary_${CEF_BUILD_VERSION}_macosx64.tar.bz2 -f --retry 5 -C -
+tar -xf ./cef_binary_${CEF_BUILD_VERSION}_macosx64.tar.bz2
+cd ./cef_binary_${CEF_BUILD_VERSION}_macosx64
+mkdir build
+cd ./build
+cmake -DCMAKE_CXX_FLAGS="-std=c++11 -stdlib=libc++" -DCMAKE_EXE_LINKER_FLAGS="-std=c++11 -stdlib=libc++" -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 ..
+make -j4
+mkdir libcef_dll
+cd ../../
diff --git a/CI/install/osx/CMakeLists.pkgproj b/CI/install/osx/CMakeLists.pkgproj
new file mode 100644
index 0000000..eff607a
--- /dev/null
+++ b/CI/install/osx/CMakeLists.pkgproj
@@ -0,0 +1,1026 @@
+
+
+
+
+ PACKAGES
+
+
+ PACKAGE_FILES
+
+ DEFAULT_INSTALL_LOCATION
+ /
+ HIERARCHY
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+ GID
+ 80
+ PATH
+ ../../../build/OBS.app
+ PATH_TYPE
+ 3
+ PERMISSIONS
+ 493
+ TYPE
+ 3
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 80
+ PATH
+ Utilities
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 1
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ Applications
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 509
+ TYPE
+ 1
+ UID
+ 0
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+
+ CHILDREN
+
+ GID
+ 80
+ PATH
+ ../../../build/plugins/obs-browser/CEF.app
+ PATH_TYPE
+ 3
+ PERMISSIONS
+ 493
+ TYPE
+ 3
+ UID
+ 0
+
+
+ CHILDREN
+
+ GID
+ 80
+ PATH
+ ../../../build/plugins/obs-browser/obs-browser.so
+ PATH_TYPE
+ 3
+ PERMISSIONS
+ 493
+ TYPE
+ 3
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ bin
+ PATH_TYPE
+ 0
+ PERMISSIONS
+ 493
+ TYPE
+ 2
+ UID
+ 0
+
+
+ GID
+ 80
+ PATH
+ obs-browser
+ 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
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Documentation
+ 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
+ 493
+ 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
+
+
+ CHILDREN
+
+ GID
+ 0
+ PATH
+ Extensions
+ 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
+ System
+ 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
+ VERSION
+ 2
+
+ PACKAGE_SCRIPTS
+
+ POSTINSTALL_PATH
+
+ PATH
+ post-install.sh
+ PATH_TYPE
+ 3
+
+ PREINSTALL_PATH
+
+ RESOURCES
+
+
+ PACKAGE_SETTINGS
+
+ AUTHENTICATION
+ 1
+ CONCLUSION_ACTION
+ 0
+ IDENTIFIER
+ org.obsproject.pkg.obs-studio
+ NAME
+ OBS
+ OVERWRITE_PERMISSIONS
+
+ VERSION
+ 1.0
+
+ UUID
+ 19CCE3F2-8911-4364-B673-8B5BC3ABD4DA
+
+
+ PACKAGE_SETTINGS
+
+ LOCATION
+ 0
+ NAME
+ SyphonInject
+
+ PATH
+
+ PATH
+ SyphonInject.pkg
+ PATH_TYPE
+ 1
+
+ TYPE
+ 1
+ UUID
+ 0CC9C67E-4D14-4794-9930-019925513B1C
+
+
+ PROJECT
+
+ PROJECT_COMMENTS
+
+ NOTES
+
+ PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M
+ IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv
+ c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l
+ cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7
+ IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250
+ ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp
+ dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u
+ dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD
+ b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjE1MDQuODEiPgo8c3R5bGUg
+ dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5
+ Pgo8L2JvZHk+CjwvaHRtbD4K
+
+
+ PROJECT_PRESENTATION
+
+ BACKGROUND
+
+ ALIGNMENT
+ 4
+ BACKGROUND_PATH
+
+ PATH
+ obs.png
+ PATH_TYPE
+ 1
+
+ CUSTOM
+ 1
+ SCALING
+ 0
+
+ INSTALLATION TYPE
+
+ HIERARCHIES
+
+ INSTALLER
+
+ LIST
+
+
+ DESCRIPTION
+
+ OPTIONS
+
+ HIDDEN
+
+ STATE
+ 0
+
+ PACKAGE_UUID
+ 19CCE3F2-8911-4364-B673-8B5BC3ABD4DA
+ REQUIREMENTS
+
+ TITLE
+
+ TOOLTIP
+
+ TYPE
+ 0
+ UUID
+ 7C540711-59F4-479C-9CFD-8C4D6594992E
+
+
+ DESCRIPTION
+
+ OPTIONS
+
+ HIDDEN
+
+ STATE
+ 1
+
+ PACKAGE_UUID
+ 0CC9C67E-4D14-4794-9930-019925513B1C
+ REQUIREMENTS
+
+ TITLE
+
+ TOOLTIP
+
+ TYPE
+ 0
+ UUID
+ BBDE08F6-D7EE-47CB-881F-7F208B3A604B
+
+
+ REMOVED
+
+
+
+ INSTALLATION TYPE
+ 0
+ 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
+
+ KEYWORDS
+
+ LOCALIZATIONS
+
+ MODE
+ 0
+
+ README
+
+ LOCALIZATIONS
+
+
+ SUMMARY
+
+ LOCALIZATIONS
+
+
+ TITLE
+
+ LOCALIZATIONS
+
+
+ LANGUAGE
+ English
+ VALUE
+ OBS
+
+
+
+
+ PROJECT_REQUIREMENTS
+
+ LIST
+
+ POSTINSTALL_PATH
+
+ PREINSTALL_PATH
+
+ RESOURCES
+
+ ROOT_VOLUME_ONLY
+
+
+ PROJECT_SETTINGS
+
+ ADVANCED_OPTIONS
+
+ BUILD_FORMAT
+ 0
+ BUILD_PATH
+
+ PATH
+ ../../../build
+ PATH_TYPE
+ 3
+
+ 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
+
+
+ TYPE
+ 0
+ VERSION
+ 2
+
+
diff --git a/CI/install/osx/OBSPublicDSAKey.pem b/CI/install/osx/OBSPublicDSAKey.pem
new file mode 100644
index 0000000..91adb40
--- /dev/null
+++ b/CI/install/osx/OBSPublicDSAKey.pem
@@ -0,0 +1,36 @@
+-----BEGIN PUBLIC KEY-----
+MIIGPDCCBC4GByqGSM44BAEwggQhAoICAQCZZZ2y7H2GJmMfP4KQihJTJOoiGNUw
+mue6sqMbH+utRykRnSKBZux6R665eRFMpNgrgFO1TLLGbdD2U31KiGtCvFJOmOl3
++QP055BuXjEG36NU7AWEFLAlbDlr/2D3oumq3Ib3iMnnr9RrVztJ2VFOvVio1eWr
+ZxboVwKPK8D6BqsWiv15vbYlJnTC4Fls6ySmdjVBxwoPlTaMu1ysi5DfbIZ93s5u
+aQt1FvXuWtPBWjyVUORcNbcWf49E5R2pV0OSBK95Hw2/wXz4vmj+w92dTePGnVaW
+Me4CoF5PIeZILwp6DCLStX4eW2WG1NChJTC8zeQ/3bMMoGyKM/MadyvrDqMywsKY
+caxkIwHrDKOEdXXGo80dIwZMMLipPA8DKhx5ojphfkeXjIhKSx+49knXT3ED5okE
+Wai7tGUXj/8D8sGh+7b+AVsdujvr4v8WQaZiKUOZ2IIHOg3VLz9T9v0zet1Yt987
+KNymFcp2CHeJ6KnDP/ZGQ6Nl0HsPxUgscsXV+R2FEc8Q1j0Ukkuxnopa0E4/huUu
+gjyRzpXD734qFMDf7LcXca6qNjBor6gVj5sRyRKCpZ+KQfMUlr8jp506ztYSyeJu
+dxJV30tQgztwkbrs02CqOt4Z3Peo6sdht7hWKSPVwmja3tq8/TfUSSoo6wKYN9/w
+Mf3dVeRF8hCzJQIVAJnzuzmzQhCKPiQnl3jh5qGII2XfAoICAQCCVATAff89ceHj
+ROHEbHTQFpVxJ/kRZPfxnU46DSw79Tih7tthV68oakPSOTP3cx/Tga0GwogarZ9N
+F2VVan5w9OQSSewXsr5UDT5bnmJF+h+JB7TMy+sXZBYobUqjlUd5VtKc8RsN86P4
+s7xbK0mA+hfe+27r18JT81/eH3xUfh7UOUGSdMN2Ch9f7RFSMZIgUAZUzu2K3ODp
+hPgtc2QJ8QVAp7GLvQgw8ZUME/ChZslyBIyJvYgUIxfxlgRWYro5pQT7/ngkgdXo
+wlghHKkldwMuY3zaFdhPnFNuEUEtc18ILsbz0+AnagCUd6n+3safskCRqLIHMOY6
+iLBSZPX9hJQhVCqSqz1VNDDww8FNa/fojJ1Lr/TI0I+0Ib2pCiY2LChXUqGY5SLZ
+2KNs5qFsyZP+I0L8YsGwqvUYyFwk7Ok224n0NtaOwqpLCrtXd/i6DaDNiaoJuwJC
+1ELCfaZivorgkC5rhBt2H7qWUAR+EtrFE/gb0k/G5EIhjYql7onGbX+G2re38vQA
+fg1pzguhig2dafP/BxMLZrn1Gg61xzmEYPuS9gclktaf675srv8GVb46VkOxXL+D
+YvTmpJPP7UUOVlmAMCo4j4y09MW3jq9TDp42VTLeZVubyjslGnavlnq1O+ZyXUye
+1FMeby65sIbSHHHwoFnRv3hLSEXI5gOCAgYAAoICAQCUkYnZkPfHfOJZI403xUYP
+CE/bLpkza074Xo6EXElsWRnpQgNTx+JFOvItgj3v0OkIqDin9UredKOwfkiftslV
+jxUVKA6I5kwnGvCpvTpQMLyLjq+VQr+J2D6eId6tV/iajhdu5r4JThU8KllT7Ywb
+NAur34ftLNCVAMRUaDNeEoHfePgderW384e+lbvpmtifmBluammGSxxRtUsdjvJZ
+BFkhaJu86CKxcU7D1lbPVOtV/jaxz6d16VdGcfBdi2LzXZzZtYpT9XGPX3NF+xii
+spAURWsoe11LTRXF+eJhgCm5iIDN3kh1HEQKYKAVpmrcM0aFzk/NpS+tFyU72vaq
+IRSSJw/aa1oELOAakG5oPldc4RcYWl32sbnVwXHO7TZvgTrBSC10o65MAC5CHP/s
+b07heDYAIt7re7szvOYq+c/9zAMAlu3pcO8MqaXYMmybdHBXHQ2b+DdJWHmIUWcX
+CbUzr09vzGkJAvqsXqbmJPr8aixrO75DhT0iDTILLWe/GWK51nf+Tg0pNxVgGyAl
+BqvRqqo7SSDu9FMkwQesFFHhuoHLyEHwVPJ+sMQTNwQcm9c6YuW8EYDRSkeKLWYk
+3fkjG+Pe9uVE8a1taDg3FjSY0UqjUT6XMw+i0Lajyus2L6wFBwrrGM6E4xa6x1CC
+MGjmuSOlPA1umQsToIcO4g==
+-----END PUBLIC KEY-----
diff --git a/CI/install/osx/SyphonInject.pkg b/CI/install/osx/SyphonInject.pkg
new file mode 100644
index 0000000..4371acc
Binary files /dev/null and b/CI/install/osx/SyphonInject.pkg differ
diff --git a/CI/install/osx/build_app.py b/CI/install/osx/build_app.py
new file mode 100644
index 0000000..907e113
--- /dev/null
+++ b/CI/install/osx/build_app.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+
+candidate_paths = "bin obs-plugins data".split()
+
+plist_path = "../cmake/osxbundle/Info.plist"
+icon_path = "../cmake/osxbundle/obs.icns"
+run_path = "../cmake/osxbundle/obslaunch.sh"
+
+#not copied
+blacklist = """/usr /System""".split()
+
+#copied
+whitelist = """/usr/local""".split()
+
+#
+#
+#
+
+
+from sys import argv
+from glob import glob
+from subprocess import check_output, call
+from collections import namedtuple
+from shutil import copy, copytree, rmtree
+from os import makedirs, rename, walk, path as ospath
+import plistlib
+
+import argparse
+
+def _str_to_bool(s):
+ """Convert string to bool (in argparse context)."""
+ if s.lower() not in ['true', 'false']:
+ raise ValueError('Need bool; got %r' % s)
+ return {'true': True, 'false': False}[s.lower()]
+
+def add_boolean_argument(parser, name, default=False):
+ """Add a boolean argument to an ArgumentParser instance."""
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument(
+ '--' + name, nargs='?', default=default, const=True, type=_str_to_bool)
+ group.add_argument('--no' + name, dest=name, action='store_false')
+
+parser = argparse.ArgumentParser(description='obs-studio package util')
+parser.add_argument('-d', '--base-dir', dest='dir', default='rundir/RelWithDebInfo')
+parser.add_argument('-n', '--build-number', dest='build_number', default='0')
+parser.add_argument('-k', '--public-key', dest='public_key', default='OBSPublicDSAKey.pem')
+parser.add_argument('-f', '--sparkle-framework', dest='sparkle', default=None)
+parser.add_argument('-b', '--base-url', dest='base_url', default='https://builds.catchexception.org/obs-studio')
+parser.add_argument('-u', '--user', dest='user', default='jp9000')
+parser.add_argument('-c', '--channel', dest='channel', default='master')
+add_boolean_argument(parser, 'stable', default=False)
+parser.add_argument('-p', '--prefix', dest='prefix', default='')
+args = parser.parse_args()
+
+def cmd(cmd):
+ import subprocess
+ import shlex
+ return subprocess.check_output(shlex.split(cmd)).rstrip('\r\n')
+
+LibTarget = namedtuple("LibTarget", ("path", "external", "copy_as"))
+
+inspect = list()
+
+inspected = set()
+
+build_path = args.dir
+build_path = build_path.replace("\\ ", " ")
+
+def add(name, external=False, copy_as=None):
+ if external and copy_as is None:
+ copy_as = name.split("/")[-1]
+ if name[0] != "/":
+ name = build_path+"/"+name
+ t = LibTarget(name, external, copy_as)
+ if t in inspected:
+ return
+ inspect.append(t)
+ inspected.add(t)
+
+
+for i in candidate_paths:
+ print("Checking " + i)
+ for root, dirs, files in walk(build_path+"/"+i):
+ for file_ in files:
+ path = root + "/" + file_
+ try:
+ out = check_output("{0}otool -L '{1}'".format(args.prefix, path), shell=True,
+ universal_newlines=True)
+ if "is not an object file" in out:
+ continue
+ except:
+ continue
+ rel_path = path[len(build_path)+1:]
+ print(repr(path), repr(rel_path))
+ add(rel_path)
+
+def add_plugins(path, replace):
+ for img in glob(path.replace(
+ "lib/QtCore.framework/Versions/5/QtCore",
+ "plugins/%s/*"%replace).replace(
+ "Library/Frameworks/QtCore.framework/Versions/5/QtCore",
+ "share/qt5/plugins/%s/*"%replace)):
+ if "_debug" in img:
+ continue
+ add(img, True, img.split("plugins/")[-1])
+
+actual_sparkle_path = '@loader_path/Frameworks/Sparkle.framework/Versions/A/Sparkle'
+
+while inspect:
+ target = inspect.pop()
+ print("inspecting", repr(target))
+ path = target.path
+ if path[0] == "@":
+ continue
+ out = check_output("{0}otool -L '{1}'".format(args.prefix, path), shell=True,
+ universal_newlines=True)
+
+ if "QtCore" in path:
+ add_plugins(path, "platforms")
+ add_plugins(path, "imageformats")
+ add_plugins(path, "accessible")
+
+
+ for line in out.split("\n")[1:]:
+ new = line.strip().split(" (")[0]
+ if '@' in new and "sparkle.framework" in new.lower():
+ actual_sparkle_path = new
+ print "Using sparkle path:", repr(actual_sparkle_path)
+ if not new or new[0] == "@" or new.endswith(path.split("/")[-1]):
+ continue
+ whitelisted = False
+ for i in whitelist:
+ if new.startswith(i):
+ whitelisted = True
+ if not whitelisted:
+ blacklisted = False
+ for i in blacklist:
+ if new.startswith(i):
+ blacklisted = True
+ break
+ if blacklisted:
+ continue
+ add(new, True)
+
+changes = list()
+for path, external, copy_as in inspected:
+ if not external:
+ continue #built with install_rpath hopefully
+ changes.append("-change '%s' '@rpath/%s'"%(path, copy_as))
+changes = " ".join(changes)
+
+info = plistlib.readPlist(plist_path)
+
+latest_tag = cmd('git describe --tags --abbrev=0')
+log = cmd('git log --pretty=oneline {0}...HEAD'.format(latest_tag))
+
+from os import path
+# set version
+if args.stable:
+ info["CFBundleVersion"] = latest_tag
+ info["CFBundleShortVersionString"] = latest_tag
+ info["SUFeedURL"] = '{0}/stable/updates.xml'.format(args.base_url)
+else:
+ info["CFBundleVersion"] = args.build_number
+ info["CFBundleShortVersionString"] = '{0}.{1}'.format(latest_tag, args.build_number)
+ info["SUFeedURL"] = '{0}/{1}/{2}/updates.xml'.format(args.base_url, args.user, args.channel)
+
+info["SUPublicDSAKeyFile"] = path.basename(args.public_key)
+info["OBSFeedsURL"] = '{0}/feeds.xml'.format(args.base_url)
+
+app_name = info["CFBundleName"]+".app"
+icon_file = "tmp/Contents/Resources/%s"%info["CFBundleIconFile"]
+
+copytree(build_path, "tmp/Contents/Resources/", symlinks=True)
+copy(icon_path, icon_file)
+plistlib.writePlist(info, "tmp/Contents/Info.plist")
+makedirs("tmp/Contents/MacOS")
+copy(run_path, "tmp/Contents/MacOS/%s"%info["CFBundleExecutable"])
+try:
+ copy(args.public_key, "tmp/Contents/Resources")
+except:
+ pass
+
+if args.sparkle is not None:
+ copytree(args.sparkle, "tmp/Contents/Frameworks/Sparkle.framework", symlinks=True)
+
+prefix = "tmp/Contents/Resources/"
+sparkle_path = '@loader_path/{0}/Frameworks/Sparkle.framework/Versions/A/Sparkle'
+
+cmd('{0}install_name_tool -change {1} {2} {3}/bin/obs'.format(
+ args.prefix, actual_sparkle_path, sparkle_path.format('../..'), prefix))
+
+
+
+for path, external, copy_as in inspected:
+ id_ = ""
+ filename = path
+ rpath = ""
+ if external:
+ id_ = "-id '@rpath/%s'"%copy_as
+ filename = prefix + "bin/" +copy_as
+ rpath = "-add_rpath @loader_path/ -add_rpath @executable_path/"
+ if "/" in copy_as:
+ try:
+ dirs = copy_as.rsplit("/", 1)[0]
+ makedirs(prefix + "bin/" + dirs)
+ except:
+ pass
+ copy(path, filename)
+ else:
+ filename = path[len(build_path)+1:]
+ id_ = "-id '@rpath/../%s'"%filename
+ if not filename.startswith("bin"):
+ print(filename)
+ rpath = "-add_rpath '@loader_path/{}/'".format(ospath.relpath("bin/", ospath.dirname(filename)))
+ filename = prefix + filename
+
+ cmd = "{0}install_name_tool {1} {2} {3} '{4}'".format(args.prefix, changes, id_, rpath, filename)
+ call(cmd, shell=True)
+
+try:
+ rename("tmp", app_name)
+except:
+ print("App already exists")
+ rmtree("tmp")
diff --git a/CI/install/osx/obs.png b/CI/install/osx/obs.png
new file mode 100644
index 0000000..364211c
--- /dev/null
+++ b/CI/install/osx/obs.png
@@ -0,0 +1,703 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ obs-studio-utils/obs.png at master · kc5nra/obs-studio-utils
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Skip to content
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Permalink
+
+
+
+
+
+
+
+
+
+ b83a806
+
+ Oct 1, 2014
+
+
+
+
+
+ 1
+ contributor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Jump to Line
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ You can't perform that action at this time.
+
+
+
+
+
+
+
+
+
+
+
+
+
You signed in with another tab or window. Reload to refresh your session.
+
You signed out in another tab or window. Reload to refresh your session.
+
+
+
+
+
+
+
+
diff --git a/CI/install/osx/package_util.py b/CI/install/osx/package_util.py
new file mode 100644
index 0000000..2ab0b94
--- /dev/null
+++ b/CI/install/osx/package_util.py
@@ -0,0 +1,94 @@
+def cmd(cmd):
+ import subprocess
+ import shlex
+ return subprocess.check_output(shlex.split(cmd)).rstrip('\r\n')
+
+def get_tag_info(tag):
+ rev = cmd('git rev-parse {0}'.format(latest_tag))
+ anno = cmd('git cat-file -p {0}'.format(rev))
+ tag_info = []
+ for i, v in enumerate(anno.splitlines()):
+ if i <= 4:
+ continue
+ tag_info.append(v.lstrip())
+
+ return tag_info
+
+def gen_html(github_user, latest_tag):
+
+ url = 'https://github.com/{0}/obs-studio/commit/%H'.format(github_user)
+
+ with open('readme.html', 'w') as f:
+ f.write("")
+ log_cmd = """git log {0}...HEAD --pretty=format:'• (view) %s '"""
+ log_res = cmd(log_cmd.format(latest_tag, url))
+ if len(log_res.splitlines()):
+ f.write('Changes since {0}: (Newest to oldest)
'.format(latest_tag))
+ f.write(log_res)
+
+ ul = False
+ f.write('')
+ import re
+
+ for l in get_tag_info(latest_tag):
+ if not len(l):
+ continue
+ if l.startswith('*'):
+ ul = True
+ if not ul:
+ f.write('
')
+ f.write('• {0} '.format(re.sub(r'^(\s*)?[*](\s*)?', '', l)))
+ else:
+ if ul:
+ f.write('
')
+ ul = False
+ f.write('{0}
'.format(l))
+ if ul:
+ f.write('')
+ f.write('
')
+
+ cmd('textutil -convert rtf readme.html -output readme.rtf')
+ cmd("""sed -i '' 's/Times-Roman/Verdana/g' readme.rtf""")
+
+def save_manifest(latest_tag, user, jenkins_build, branch, stable):
+ log = cmd('git log --pretty=oneline {0}...HEAD'.format(latest_tag))
+ manifest = {}
+ manifest['commits'] = []
+ for v in log.splitlines():
+ manifest['commits'].append(v)
+ manifest['tag'] = {
+ 'name': latest_tag,
+ 'description': get_tag_info(latest_tag)
+ }
+
+ manifest['version'] = cmd('git rev-list HEAD --count')
+ manifest['sha1'] = cmd('git rev-parse HEAD')
+ manifest['jenkins_build'] = jenkins_build
+
+ manifest['user'] = user
+ manifest['branch'] = branch
+ manifest['stable'] = stable
+
+ import cPickle
+ with open('manifest', 'w') as f:
+ cPickle.dump(manifest, f)
+
+def prepare_pkg(project, package_id):
+ cmd('packagesutil --file "{0}" set package-1 identifier {1}'.format(project, package_id))
+ cmd('packagesutil --file "{0}" set package-1 version {1}'.format(project, '1.0'))
+
+
+import argparse
+parser = argparse.ArgumentParser(description='obs-studio package util')
+parser.add_argument('-u', '--user', dest='user', default='jp9000')
+parser.add_argument('-p', '--package-id', dest='package_id', default='org.obsproject.pkg.obs-studio')
+parser.add_argument('-f', '--project-file', dest='project', default='OBS.pkgproj')
+parser.add_argument('-j', '--jenkins-build', dest='jenkins_build', default='0')
+parser.add_argument('-b', '--branch', dest='branch', default='master')
+parser.add_argument('-s', '--stable', dest='stable', required=False, action='store_true', default=False)
+args = parser.parse_args()
+
+latest_tag = cmd('git describe --tags --abbrev=0')
+gen_html(args.user, latest_tag)
+prepare_pkg(args.project, args.package_id)
+save_manifest(latest_tag, args.user, args.jenkins_build, args.branch, args.stable)
diff --git a/CI/install/osx/post-install.sh b/CI/install/osx/post-install.sh
new file mode 100644
index 0000000..f55ae58
--- /dev/null
+++ b/CI/install/osx/post-install.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+# Fix permissions on CEF
+chmod 744 "/Library/Application Support/obs-studio/plugins/obs-browser/bin/CEF.app/Contents/Info.plist"
+chmod 744 "/Library/Application Support/obs-studio/plugins/obs-browser/bin/CEF.app/Contents/Frameworks/CEF Helper.app/Contents/Info.plist"
diff --git a/CI/osxcert/Certificates.p12.enc b/CI/osxcert/Certificates.p12.enc
new file mode 100644
index 0000000..0fb42bc
Binary files /dev/null and b/CI/osxcert/Certificates.p12.enc differ
diff --git a/CI/util/build-package-deps-osx.sh b/CI/util/build-package-deps-osx.sh
new file mode 100755
index 0000000..bf950d7
--- /dev/null
+++ b/CI/util/build-package-deps-osx.sh
@@ -0,0 +1,130 @@
+#!/usr/bin/env bash
+
+CURDIR=$(pwd)
+
+# the temp directory
+WORK_DIR=`mktemp -d`
+
+# deletes the temp directory
+function cleanup {
+ #rm -rf "$WORK_DIR"
+ echo "Deleted temp working directory $WORK_DIR"
+}
+
+# register the cleanup function to be called on the EXIT signal
+trap cleanup EXIT
+
+cd $WORK_DIR
+
+DEPS_DEST=$WORK_DIR/obsdeps
+
+# make dest dirs
+mkdir $DEPS_DEST
+mkdir $DEPS_DEST/bin
+mkdir $DEPS_DEST/include
+
+# OSX COMPAT
+export MACOSX_DEPLOYMENT_TARGET=10.9
+
+# If you need an olders SDK and Xcode won't give it to you
+# https://github.com/phracker/MacOSX-SDKs
+
+# libopus
+curl -L -O http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz
+tar -xf opus-1.1.3.tar.gz
+cd ./opus-1.1.3
+mkdir build
+cd ./build
+../configure --disable-shared --enable-static --prefix="/tmp/obsdeps"
+make -j 12
+make install
+
+cd $WORK_DIR
+
+# libogg
+curl -L -O http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.gz
+tar -xf libogg-1.3.2.tar.gz
+cd ./libogg-1.3.2
+mkdir build
+cd ./build
+../configure --disable-shared --enable-static --prefix="/tmp/obsdeps"
+make -j 12
+make install
+
+cd $WORK_DIR
+
+# libvorbis
+curl -L -O http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.gz
+tar -xf libvorbis-1.3.5.tar.gz
+cd ./libvorbis-1.3.5
+mkdir build
+cd ./build
+../configure --disable-shared --enable-static --prefix="/tmp/obsdeps"
+make -j 12
+make install
+
+cd $WORK_DIR
+
+# libvpx
+curl -L -O http://storage.googleapis.com/downloads.webmproject.org/releases/webm/libvpx-1.6.0.tar.bz2
+tar -xf libvpx-1.6.0.tar.bz2
+cd ./libvpx-1.6.0
+mkdir build
+cd ./build
+../configure --disable-shared --libdir="/tmp/obsdeps/bin"
+make -j 12
+make install
+
+cd $WORK_DIR
+
+# x264
+git clone git://git.videolan.org/x264.git
+cd ./x264
+mkdir build
+cd ./build
+../configure --extra-ldflags="-mmacosx-version-min=10.9" --enable-static --prefix="/tmp/obsdeps"
+make -j 12
+make install
+../configure --extra-ldflags="-mmacosx-version-min=10.9" --enable-shared --libdir="/tmp/obsdeps/bin" --prefix="/tmp/obsdeps"
+make -j 12
+ln -f -s libx264.*.dylib libx264.dylib
+find . -name \*.dylib -exec cp \{\} $DEPS_DEST/bin/ \;
+rsync -avh --include="*/" --include="*.h" --exclude="*" ../* $DEPS_DEST/include/
+rsync -avh --include="*/" --include="*.h" --exclude="*" ./* $DEPS_DEST/include/
+
+cd $WORK_DIR
+
+# janson
+curl -L -O http://www.digip.org/jansson/releases/jansson-2.9.tar.gz
+tar -xf jansson-2.9.tar.gz
+cd jansson-2.9
+mkdir build
+cd ./build
+../configure --libdir="/tmp/obsdeps/bin" --enable-shared --disable-static
+make -j 12
+find . -name \*.dylib -exec cp \{\} $DEPS_DEST/bin/ \;
+rsync -avh --include="*/" --include="*.h" --exclude="*" ../* $DEPS_DEST/include/
+rsync -avh --include="*/" --include="*.h" --exclude="*" ./* $DEPS_DEST/include/
+
+cd $WORK_DIR
+
+export LDFLAGS="-L/tmp/obsdeps/lib"
+export CFLAGS="-I/tmp/obsdeps/include"
+
+# FFMPEG
+curl -L -O https://github.com/FFmpeg/FFmpeg/archive/n3.2.2.zip
+unzip ./n3.2.2.zip
+cd ./FFmpeg-n3.2.2
+mkdir build
+cd ./build
+../configure --extra-ldflags="-mmacosx-version-min=10.9" --enable-shared --disable-static --shlibdir="/tmp/obsdeps/bin" --enable-gpl --disable-doc --enable-libx264 --enable-libopus --enable-libvorbis --enable-libvpx
+make -j 12
+find . -name \*.dylib -exec cp \{\} $DEPS_DEST/bin/ \;
+rsync -avh --include="*/" --include="*.h" --exclude="*" ../* $DEPS_DEST/include/
+rsync -avh --include="*/" --include="*.h" --exclude="*" ./* $DEPS_DEST/include/
+
+cd $WORK_DIR
+
+tar -czf osx-deps.tar.gz obsdeps
+
+cp ./osx-deps.tar.gz $CURDIR
\ No newline at end of file
diff --git a/CI/util/win32.sh b/CI/util/win32.sh
new file mode 100755
index 0000000..a1a2919
--- /dev/null
+++ b/CI/util/win32.sh
@@ -0,0 +1,69 @@
+#/bin/bash
+
+cd x264
+make clean
+LDFLAGS="-static-libgcc" ./configure --enable-shared --enable-win32thread --disable-avs --disable-ffms --disable-gpac --disable-interlaced --disable-lavf --cross-prefix=i686-w64-mingw32- --host=i686-pc-mingw32 --prefix="/home/jim/packages/win32"
+make -j6 fprofiled VIDS="CITY_704x576_60_orig_01.yuv"
+make install
+i686-w64-mingw32-dlltool -z /home/jim/packages/win32/bin/x264.orig.def --export-all-symbols /home/jim/packages/win32/bin/libx264-148.dll
+grep "EXPORTS\|x264" /home/jim/packages/win32/bin/x264.orig.def > /home/jim/packages/win32/bin/x264.def
+rm -f /home/jim/packages/win32/bin/x264.org.def
+sed -i -e "/\\t.*DATA/d" -e "/\\t\".*/d" -e "s/\s@.*//" /home/jim/packages/win32/bin/x264.def
+i686-w64-mingw32-dlltool -m i386 -d /home/jim/packages/win32/bin/x264.def -l /home/jim/packages/win32/bin/x264.lib -D /home/jim/win32/packages/bin/libx264-148.dll
+cd ..
+
+cd opus
+make clean
+LDFLAGS="-static-libgcc" ./configure -host=i686-w64-mingw32 --prefix="/home/jim/packages/win32" --enable-shared
+make -j6
+make install
+cd ..
+
+cd zlib/build32
+make clean
+cmake .. -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_C_COMPILER=i686-w64-mingw32-gcc -DCMAKE_INSTALL_PREFIX=/home/jim/packages/win32 -DINSTALL_PKGCONFIG_DIR=/home/jim/packages/win32/lib/pkgconfig -DCMAKE_RC_COMPILER=i686-w64-mingw32-windres -DCMAKE_SHARED_LINKER_FLAGS="-static-libgcc"
+make -j6
+make install
+mv ../../win32/lib/libzlib.dll.a ../../win32/lib/libz.dll.a
+mv ../../win32/lib/libzlibstatic.a ../../win32/lib/libz.a
+cp ../win32/zlib.def /home/jim/packages/win32/bin
+i686-w64-mingw32-dlltool -m i386 -d ../win32/zlib.def -l /home/jim/packages/win32/bin/zlib.lib -D /home/jim/win32/packages/bin/zlib.dll
+cd ../..
+
+cd libpng
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win32/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win32/lib -static-libgcc" CPPFLAGS="-I/home/jim/packages/win32/include" ./configure -host=i686-w64-mingw32 --prefix="/home/jim/packages/win32" --enable-shared
+make -j6
+make install
+cd ..
+
+cd libogg
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win32/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win32/lib -static-libgcc" CPPFLAGS="-I/home/jim/packages/win32/include" ./configure -host=i686-w64-mingw32 --prefix="/home/jim/packages/win32" --enable-shared
+make -j6
+make install
+cd ..
+
+cd libvorbis
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win32/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win32/lib -static-libgcc" CPPFLAGS="-I/home/jim/packages/win32/include" ./configure -host=i686-w64-mingw32 --prefix="/home/jim/packages/win32" --enable-shared --with-ogg="/home/jim/packages/win32"
+make -j6
+make install
+cd ..
+
+cd libvpxbuild
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win32/lib/pkgconfig" CROSS=i686-w64-mingw32- LDFLAGS="-static-libgcc" ../libvpx/configure --prefix=/home/jim/packages/win32 --enable-vp8 --enable-vp9 --disable-docs --disable-examples --enable-shared --disable-static --enable-runtime-cpu-detect --enable-realtime-only --disable-install-bins --disable-install-docs --disable-unit-tests --target=x86-win32-gcc
+make -j6
+make install
+i686-w64-mingw32-dlltool -m i386 -d libvpx.def -l /home/jim/packages/win32/bin/vpx.lib -D /home/jim/win32/packages/bin/libvpx-1.dll
+cd ..
+
+cd ffmpeg
+make clean
+cp /media/sf_linux/nvEncodeAPI.h /home/jim/packages/win32/include
+PKG_CONFIG_PATH="/home/jim/packages/win32/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win32/lib -static-libgcc" CFLAGS="-I/home/jim/packages/win32/include" ./configure --enable-memalign-hack --enable-gpl --disable-programs --disable-doc --arch=x86 --enable-shared --enable-nvenc --enable-libx264 --enable-libopus --enable-libvorbis --enable-libvpx --disable-debug --cross-prefix=i686-w64-mingw32- --target-os=mingw32 --pkg-config=pkg-config --prefix="/home/jim/packages/win32" --disable-postproc
+read -n1 -r -p "Press any key to continue building FFmpeg..." key
+make -j6
+make install
+cd ..
diff --git a/CI/util/win64.sh b/CI/util/win64.sh
new file mode 100755
index 0000000..1ff9788
--- /dev/null
+++ b/CI/util/win64.sh
@@ -0,0 +1,69 @@
+#/bin/bash
+
+cd x264
+make clean
+LDFLAGS="-static-libgcc" ./configure --enable-shared --enable-win32thread --disable-avs --disable-ffms --disable-gpac --disable-interlaced --disable-lavf --cross-prefix=x86_64-w64-mingw32- --host=x86_64-pc-mingw32 --prefix="/home/jim/packages/win64"
+make -j6 fprofiled VIDS="CITY_704x576_60_orig_01.yuv"
+make install
+x86_64-w64-mingw32-dlltool -z /home/jim/packages/win64/bin/x264.orig.def --export-all-symbols /home/jim/packages/win64/bin/libx264-148.dll
+grep "EXPORTS\|x264" /home/jim/packages/win64/bin/x264.orig.def > /home/jim/packages/win64/bin/x264.def
+rm -f /home/jim/packages/win64/bin/x264.org.def
+sed -i -e "/\\t.*DATA/d" -e "/\\t\".*/d" -e "s/\s@.*//" /home/jim/packages/win64/bin/x264.def
+x86_64-w64-mingw32-dlltool -m i386:x86-64 -d /home/jim/packages/win64/bin/x264.def -l /home/jim/packages/win64/bin/x264.lib -D /home/jim/win64/packages/bin/libx264-148.dll
+cd ..
+
+cd opus
+make clean
+LDFLAGS="-static-libgcc" ./configure -host=x86_64-w64-mingw32 --prefix="/home/jim/packages/win64" --enable-shared
+make -j6
+make install
+cd ..
+
+cd zlib/build64
+make clean
+cmake .. -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_INSTALL_PREFIX=/home/jim/packages/win64 -DCMAKE_RC_COMPILER=x86_64-w64-mingw32-windres -DCMAKE_SHARED_LINKER_FLAGS="-static-libgcc"
+make -j6
+make install
+mv ../../win64/lib/libzlib.dll.a ../../win64/lib/libz.dll.a
+mv ../../win64/lib/libzlibstatic.a ../../win64/lib/libz.a
+cp ../win64/zlib.def /home/jim/packages/win64/bin
+x86_64-w64-mingw32-dlltool -m i386:x86-64 -d ../win32/zlib.def -l /home/jim/packages/win64/bin/zlib.lib -D /home/jim/win64/packages/bin/zlib.dll
+cd ../..
+
+cd libpng
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win64/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win64/lib" CPPFLAGS="-I/home/jim/packages/win64/include" ./configure -host=x86_64-w64-mingw32 --prefix="/home/jim/packages/win64" --enable-shared
+make -j6
+make install
+cd ..
+
+cd libogg
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win64/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win64/lib -static-libgcc" CPPFLAGS="-I/home/jim/packages/win64/include" ./configure -host=x86_64-w64-mingw32 --prefix="/home/jim/packages/win64" --enable-shared
+make -j6
+make install
+cd ..
+
+cd libvorbis
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win64/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win64/lib -static-libgcc" CPPFLAGS="-I/home/jim/packages/win64/include" ./configure -host=x86_64-w64-mingw32 --prefix="/home/jim/packages/win64" --enable-shared --with-ogg="/home/jim/packages/win64"
+make -j6
+make install
+cd ..
+
+cd libvpxbuild
+make clean
+PKG_CONFIG_PATH="/home/jim/packages/win64/lib/pkgconfig" CROSS=x86_64-w64-mingw32- LDFLAGS="-static-libgcc" ../libvpx/configure --prefix=/home/jim/packages/win64 --enable-vp8 --enable-vp9 --disable-docs --disable-examples --enable-shared --disable-static --enable-runtime-cpu-detect --enable-realtime-only --disable-install-bins --disable-install-docs --disable-unit-tests --target=x86_64-win64-gcc
+make -j6
+make install
+x86_64-w64-mingw32-dlltool -m i386:x86-64 -d libvpx.def -l /home/jim/packages/win64/bin/vpx.lib -D /home/jim/win64/packages/bin/libvpx-1.dll
+cd ..
+
+cd ffmpeg
+make clean
+cp /media/sf_linux/nvEncodeAPI.h /home/jim/packages/win64/include
+PKG_CONFIG_PATH="/home/jim/packages/win64/lib/pkgconfig" LDFLAGS="-L/home/jim/packages/win64/lib" CPPFLAGS="-I/home/jim/packages/win64/include" ./configure --enable-memalign-hack --enable-gpl --disable-doc --arch=x86_64 --enable-shared --enable-nvenc --enable-libx264 --enable-libopus --enable-libvorbis --enable-libvpx --disable-debug --cross-prefix=x86_64-w64-mingw32- --target-os=mingw32 --pkg-config=pkg-config --prefix="/home/jim/packages/win64" --disable-postproc
+read -n1 -r -p "Press any key to continue building FFmpeg..." key
+make -j6
+make install
+cd ..
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fafd698..4e14579 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,23 @@ cmake_minimum_required(VERSION 2.8.12)
project(obs-studio)
+option(BUILD_CAPTIONS "Build captions" FALSE)
+
+if(WIN32)
+ if (QTDIR OR DEFINED ENV{QTDIR} OR DEFINED ENV{QTDIR32} OR DEFINED ENV{QTDIR64})
+ # Qt path set by user or env var
+ else()
+ set(QTDIR "" CACHE PATH "Path to Qt (e.g. C:/Qt/5.7/msvc2015_64)")
+ message(WARNING "QTDIR variable is missing. Please set this variable to specify path to Qt (e.g. C:/Qt/5.7/msvc2015_64)")
+ endif()
+ if (DepsPath OR DEFINED ENV{DepsPath} OR DEFINED ENV{DepsPath32} OR DEFINED ENV{DepsPath64})
+ # Dependencies path set by user or env var
+ else()
+ set(DepsPath "" CACHE PATH "Path to compiled dependencies (e.g. D:/dependencies/win64)")
+ message(WARNING "DepsPath variable is missing. Please set this variable to specify path to compiled dependencies (e.g. D:/dependencies/win64)")
+ endif()
+endif()
+
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
include(ObsHelpers)
@@ -45,7 +62,7 @@ elseif(MSVC)
endif()
if(WIN32)
- add_definitions(-DUNICODE -D_UNICODE)
+ add_definitions(-DUNICODE -D_UNICODE -D_CRT_SECURE_NO_WARNINGS)
endif()
if(MSVC)
diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt
index 69cd693..0dae204 100644
--- a/UI/CMakeLists.txt
+++ b/UI/CMakeLists.txt
@@ -14,6 +14,8 @@ add_subdirectory(obs-frontend-api)
project(obs)
+set(ENABLE_WIN_UPDATER FALSE CACHE BOOL "Enable the windows updater")
+
if(DEFINED QTDIR${_lib_suffix})
list(APPEND CMAKE_PREFIX_PATH "${QTDIR${_lib_suffix}}")
elseif(DEFINED QTDIR)
@@ -52,9 +54,27 @@ include_directories(${LIBCURL_INCLUDE_DIRS})
add_definitions(${LIBCURL_DEFINITIONS})
if(WIN32)
+ include_directories(${OBS_JANSSON_INCLUDE_DIRS})
+ include_directories(${BLAKE2_INCLUDE_DIR})
+
set(obs_PLATFORM_SOURCES
platform-windows.cpp
+ win-update/update-window.cpp
+ win-update/win-update.cpp
+ win-update/win-update-helpers.cpp
obs.rc)
+ set(obs_PLATFORM_HEADERS
+ win-update/update-window.hpp
+ win-update/win-update.hpp
+ win-update/win-update-helpers.hpp)
+ set(obs_PLATFORM_LIBRARIES
+ crypt32
+ blake2
+ ${OBS_JANSSON_IMPORT})
+
+ if(ENABLE_WIN_UPDATER)
+ add_definitions(-DENABLE_WIN_UPDATER)
+ endif()
elseif(APPLE)
set(obs_PLATFORM_SOURCES
platform-osx.mm)
@@ -83,19 +103,7 @@ elseif(UNIX)
set(obs_PLATFORM_SOURCES
platform-x11.cpp)
- find_package(XCB COMPONENTS XCB REQUIRED RANDR REQUIRED XINERAMA REQUIRED)
-
- include_directories(
- ${XCB_INCLUDE_DIRS}
- ${X11_XCB_INCLUDE_DIRS})
-
- add_definitions(
- ${XCB_DEFINITIONS}
- ${X11_XCB_DEFINITIONS})
-
- set(obs_PLATFORM_LIBRARIES
- ${XCB_LIBRARIES}
- ${X11_XCB_LIBRARIES}
+ set(obs_PLATFORM_LIBRARIES
Qt5::X11Extras)
endif()
@@ -144,6 +152,7 @@ set(obs_SOURCES
qt-wrappers.cpp)
set(obs_HEADERS
+ ${obs_PLATFORM_HEADERS}
obs-app.hpp
platform.hpp
window-main.hpp
@@ -196,6 +205,7 @@ set(obs_UI
forms/OBSBasicSettings.ui
forms/OBSBasicSourceSelect.ui
forms/OBSBasicInteraction.ui
+ forms/OBSUpdate.ui
forms/OBSRemux.ui)
set(obs_QRC
@@ -242,3 +252,6 @@ if (UNIX AND UNIX_STRUCTURE AND NOT APPLE)
endif()
add_subdirectory(frontend-plugins)
+if(WIN32)
+ add_subdirectory(win-update/updater)
+endif()
diff --git a/UI/adv-audio-control.cpp b/UI/adv-audio-control.cpp
index c17f900..b7bfd4d 100644
--- a/UI/adv-audio-control.cpp
+++ b/UI/adv-audio-control.cpp
@@ -2,9 +2,11 @@
#include
#include
#include
+#include
#include
#include
#include "qt-wrappers.hpp"
+#include "obs-app.hpp"
#include "adv-audio-control.hpp"
#ifndef NSEC_PER_MSEC
@@ -30,11 +32,16 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_)
volume = new QSpinBox();
forceMono = new QCheckBox();
panning = new QSlider(Qt::Horizontal);
+#if defined(_WIN32) || defined(__APPLE__)
+ monitoringType = new QComboBox();
+#endif
syncOffset = new QSpinBox();
mixer1 = new QCheckBox();
mixer2 = new QCheckBox();
mixer3 = new QCheckBox();
mixer4 = new QCheckBox();
+ mixer5 = new QCheckBox();
+ mixer6 = new QCheckBox();
volChangedSignal.Connect(handler, "volume", OBSSourceVolumeChanged,
this);
@@ -85,6 +92,19 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_)
syncOffset->setMaximum(20000);
syncOffset->setValue(int(cur_sync / NSEC_PER_MSEC));
+ int idx;
+#if defined(_WIN32) || defined(__APPLE__)
+ monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.None"),
+ (int)OBS_MONITORING_TYPE_NONE);
+ monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.MonitorOnly"),
+ (int)OBS_MONITORING_TYPE_MONITOR_ONLY);
+ monitoringType->addItem(QTStr("Basic.AdvAudio.Monitoring.Both"),
+ (int)OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT);
+ int mt = (int)obs_source_get_monitoring_type(source);
+ idx = monitoringType->findData(mt);
+ monitoringType->setCurrentIndex(idx);
+#endif
+
mixer1->setText("1");
mixer1->setChecked(mixers & (1<<0));
mixer2->setText("2");
@@ -93,6 +113,10 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_)
mixer3->setChecked(mixers & (1<<2));
mixer4->setText("4");
mixer4->setChecked(mixers & (1<<3));
+ mixer5->setText("5");
+ mixer5->setChecked(mixers & (1<<4));
+ mixer6->setText("6");
+ mixer6->setChecked(mixers & (1<<5));
panningContainer->layout()->addWidget(labelL);
panningContainer->layout()->addWidget(panning);
@@ -103,6 +127,8 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_)
mixerContainer->layout()->addWidget(mixer2);
mixerContainer->layout()->addWidget(mixer3);
mixerContainer->layout()->addWidget(mixer4);
+ mixerContainer->layout()->addWidget(mixer5);
+ mixerContainer->layout()->addWidget(mixer6);
QWidget::connect(volume, SIGNAL(valueChanged(int)),
this, SLOT(volumeChanged(int)));
@@ -112,6 +138,10 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_)
this, SLOT(panningChanged(int)));
QWidget::connect(syncOffset, SIGNAL(valueChanged(int)),
this, SLOT(syncOffsetChanged(int)));
+#if defined(_WIN32) || defined(__APPLE__)
+ QWidget::connect(monitoringType, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(monitoringTypeChanged(int)));
+#endif
QWidget::connect(mixer1, SIGNAL(clicked(bool)),
this, SLOT(mixer1Changed(bool)));
QWidget::connect(mixer2, SIGNAL(clicked(bool)),
@@ -120,15 +150,23 @@ OBSAdvAudioCtrl::OBSAdvAudioCtrl(QGridLayout *layout, obs_source_t *source_)
this, SLOT(mixer3Changed(bool)));
QWidget::connect(mixer4, SIGNAL(clicked(bool)),
this, SLOT(mixer4Changed(bool)));
+ QWidget::connect(mixer5, SIGNAL(clicked(bool)),
+ this, SLOT(mixer5Changed(bool)));
+ QWidget::connect(mixer6, SIGNAL(clicked(bool)),
+ this, SLOT(mixer6Changed(bool)));
int lastRow = layout->rowCount();
- layout->addWidget(nameLabel, lastRow, 0);
- layout->addWidget(volume, lastRow, 1);
- layout->addWidget(forceMonoContainer, lastRow, 2);
- layout->addWidget(panningContainer, lastRow, 3);
- layout->addWidget(syncOffset, lastRow, 4);
- layout->addWidget(mixerContainer, lastRow, 5);
+ idx = 0;
+ layout->addWidget(nameLabel, lastRow, idx++);
+ layout->addWidget(volume, lastRow, idx++);
+ layout->addWidget(forceMonoContainer, lastRow, idx++);
+ layout->addWidget(panningContainer, lastRow, idx++);
+ layout->addWidget(syncOffset, lastRow, idx++);
+#if defined(_WIN32) || defined(__APPLE__)
+ layout->addWidget(monitoringType, lastRow, idx++);
+#endif
+ layout->addWidget(mixerContainer, lastRow, idx++);
layout->layout()->setAlignment(mixerContainer,
Qt::AlignHCenter | Qt::AlignVCenter);
}
@@ -140,6 +178,9 @@ OBSAdvAudioCtrl::~OBSAdvAudioCtrl()
forceMonoContainer->deleteLater();
panningContainer->deleteLater();
syncOffset->deleteLater();
+#if defined(_WIN32) || defined(__APPLE__)
+ monitoringType->deleteLater();
+#endif
mixerContainer->deleteLater();
}
@@ -209,6 +250,8 @@ void OBSAdvAudioCtrl::SourceMixersChanged(uint32_t mixers)
setCheckboxState(mixer2, mixers & (1<<1));
setCheckboxState(mixer3, mixers & (1<<2));
setCheckboxState(mixer4, mixers & (1<<3));
+ setCheckboxState(mixer5, mixers & (1<<4));
+ setCheckboxState(mixer6, mixers & (1<<5));
}
/* ------------------------------------------------------------------------- */
@@ -250,6 +293,29 @@ void OBSAdvAudioCtrl::syncOffsetChanged(int milliseconds)
int64_t(milliseconds) * NSEC_PER_MSEC);
}
+void OBSAdvAudioCtrl::monitoringTypeChanged(int index)
+{
+ int mt = monitoringType->itemData(index).toInt();
+ obs_source_set_monitoring_type(source, (obs_monitoring_type)mt);
+
+ const char *type = nullptr;
+
+ switch (mt) {
+ case OBS_MONITORING_TYPE_NONE:
+ type = "none";
+ break;
+ case OBS_MONITORING_TYPE_MONITOR_ONLY:
+ type = "monitor only";
+ break;
+ case OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT:
+ type = "monitor and output";
+ break;
+ }
+
+ blog(LOG_INFO, "User changed audio monitoring for source '%s' to: %s",
+ obs_source_get_name(source), type);
+}
+
static inline void setMixer(obs_source_t *source, const int mixerIdx,
const bool checked)
{
@@ -281,3 +347,13 @@ void OBSAdvAudioCtrl::mixer4Changed(bool checked)
{
setMixer(source, 3, checked);
}
+
+void OBSAdvAudioCtrl::mixer5Changed(bool checked)
+{
+ setMixer(source, 4, checked);
+}
+
+void OBSAdvAudioCtrl::mixer6Changed(bool checked)
+{
+ setMixer(source, 5, checked);
+}
diff --git a/UI/adv-audio-control.hpp b/UI/adv-audio-control.hpp
index 1b16c6e..38d7608 100644
--- a/UI/adv-audio-control.hpp
+++ b/UI/adv-audio-control.hpp
@@ -9,6 +9,7 @@ class QLabel;
class QSpinBox;
class QCheckBox;
class QSlider;
+class QComboBox;
class OBSAdvAudioCtrl : public QObject {
Q_OBJECT
@@ -27,10 +28,13 @@ private:
QPointer labelL;
QPointer labelR;
QPointer syncOffset;
+ QPointer monitoringType;
QPointer mixer1;
QPointer mixer2;
QPointer mixer3;
QPointer mixer4;
+ QPointer mixer5;
+ QPointer mixer6;
OBSSignal volChangedSignal;
OBSSignal syncOffsetSignal;
@@ -58,8 +62,11 @@ public slots:
void downmixMonoChanged(bool checked);
void panningChanged(int val);
void syncOffsetChanged(int milliseconds);
+ void monitoringTypeChanged(int index);
void mixer1Changed(bool checked);
void mixer2Changed(bool checked);
void mixer3Changed(bool checked);
void mixer4Changed(bool checked);
+ void mixer5Changed(bool checked);
+ void mixer6Changed(bool checked);
};
diff --git a/UI/api-interface.cpp b/UI/api-interface.cpp
index 390c1da..4612100 100644
--- a/UI/api-interface.cpp
+++ b/UI/api-interface.cpp
@@ -231,7 +231,22 @@ struct OBSStudioAPI : obs_frontend_callbacks {
bool obs_frontend_recording_active(void) override
{
- return main->outputHandler->StreamingActive();
+ return main->outputHandler->RecordingActive();
+ }
+
+ void obs_frontend_replay_buffer_start(void) override
+ {
+ QMetaObject::invokeMethod(main, "StartReplayBuffer");
+ }
+
+ void obs_frontend_replay_buffer_stop(void) override
+ {
+ QMetaObject::invokeMethod(main, "StopReplayBuffer");
+ }
+
+ bool obs_frontend_replay_buffer_active(void) override
+ {
+ return main->outputHandler->ReplayBufferActive();
}
void *obs_frontend_add_tools_menu_qaction(const char *name) override
@@ -286,6 +301,13 @@ struct OBSStudioAPI : obs_frontend_callbacks {
return out;
}
+ obs_output_t *obs_frontend_get_replay_buffer_output(void) override
+ {
+ OBSOutput out = main->outputHandler->replayBuffer;
+ obs_output_addref(out);
+ return out;
+ }
+
config_t *obs_frontend_get_profile_config(void) override
{
return main->basicConfig;
diff --git a/UI/data/locale/ar-SA.ini b/UI/data/locale/ar-SA.ini
index af10eca..f4ad127 100644
--- a/UI/data/locale/ar-SA.ini
+++ b/UI/data/locale/ar-SA.ini
@@ -49,6 +49,7 @@ Right="يمين"
Top="أعلى"
Bottom="أسفل"
+
QuickTransitions.SwapScenes="التبديل بين مشهدي المعاينة و الاخراج بعد عملية الانتقال"
QuickTransitions.SwapScenesTT="يقوم بتبديل مشهد المعاينة مع مشهد الاخراج بعد عملية الانتقال بين المشاهد (اذا كان مشهد الاخراج الاصلي لازال موجوداً) \n هذا لن يقوم بالتراجع عن اي تغييرات قمت بها على مشهد الاخراج الأصلي."
QuickTransitions.DuplicateScene="استنساخ المشهد"
@@ -58,7 +59,6 @@ QuickTransitions.EditPropertiesTT="عند تحرير المشهد نفسه، ي
QuickTransitions.HotkeyName="الانتقال السريع: %1"
Basic.AddTransition="إضافة المراحل الانتقالية للتكوين"
-Basic.RemoveTransition="سلاو"
Basic.TransitionProperties="خصائص تأثير الإنتقال"
Basic.SceneTransitions="تأثير انتقال المشهد"
Basic.TransitionDuration="مدة الانتقال"
@@ -88,6 +88,7 @@ ConfirmExit.Text="OBS حالياً نشط، كافة عمليات البث/ال
ConfirmRemove.Title="تأكيد الإزالة"
ConfirmRemove.Text="هل أنت متأكد من رغبتك في إزالة '$1' ?"
+
Output.ConnectFail.Title="فشل في الاتصال"
Output.ConnectFail.BadPath="مسار أو رابط الاتصال غير صالح. الرجاء التحقق من الإعدادات للتحقق من كونه صالح."
Output.ConnectFail.ConnectFailed="فشل الاتصال بالسيرفر"
@@ -148,6 +149,7 @@ ScaleFiltering.Point="نقطة"
Deinterlacing.Discard="تجاهل"
+
Basic.Main.AddSceneDlg.Title="أضف المشهد"
Basic.Main.AddSceneDlg.Text="الرجاء إدخال اسم المشهد"
diff --git a/UI/data/locale/bg-BG.ini b/UI/data/locale/bg-BG.ini
index 260ebfe..33ddabe 100644
--- a/UI/data/locale/bg-BG.ini
+++ b/UI/data/locale/bg-BG.ini
@@ -45,6 +45,7 @@ ResetOSXVSyncOnExit="Рестартиране на OSX V-синхронизац
+
TitleBar.Profile="Профил"
TitleBar.Scenes="Сцени"
@@ -61,6 +62,7 @@ ConfirmExit.Title="Изход от OBS?"
ConfirmRemove.Title="Потвърди премахване"
ConfirmRemove.Text="Наистина ли искате да премахнете \"$1\"?"
+
Output.ConnectFail.Title="Неуспешно свързване"
Output.ConnectFail.BadPath="Невалиден път или URL. Проверете дали настройките ви са валидни."
Output.ConnectFail.ConnectFailed="Неуспешна връзка със сървъра"
@@ -112,6 +114,7 @@ Basic.Main.PreviewConextMenu.Enable="Разреши преглед"
+
Basic.Main.AddSceneDlg.Title="Добави сцена"
Basic.Main.AddSceneDlg.Text="Моля, въведете името на сцената"
@@ -284,10 +287,6 @@ Basic.AdvAudio.Volume="Сила на звука (%)"
Basic.Settings.Hotkeys="Горещи клавиши"
-Basic.Hotkeys.StartStreaming="Започни стрийм"
-Basic.Hotkeys.StopStreaming="Спри стрийм"
-Basic.Hotkeys.StartRecording="Започни запис"
-Basic.Hotkeys.StopRecording="Спри запис"
Basic.Hotkeys.SelectScene="Премини към сцена"
diff --git a/UI/data/locale/ca-ES.ini b/UI/data/locale/ca-ES.ini
index a688099..8242139 100644
--- a/UI/data/locale/ca-ES.ini
+++ b/UI/data/locale/ca-ES.ini
@@ -49,13 +49,33 @@ Right="Dreta"
Top="Part superior"
Bottom="Part inferior"
Reset="Restableix"
+Hours="Hores"
+Minutes="Minuts"
+Seconds="Segons"
+Deprecated="Obsolet"
+ReplayBuffer="Memòria intermèdia de reproducció"
+Import="Importa"
+Export="Exporta"
+
+Updater.Title="Nova actualització disponible"
+Updater.Text="Hi ha una nova actualització disponible:"
+Updater.UpdateNow="Actualitza ara"
+Updater.RemindMeLater="Recordeu-m'ho més tard"
+Updater.Skip="Omet la versió"
+Updater.Running.Title="Programa actualment actiu"
+Updater.Running.Text="Les sortides estan actives actualment, apagueu qualsevol sortida activa abans d'intentar actualitzar"
+Updater.NoUpdatesAvailable.Title="No hi ha actualitzacions disponibles"
+Updater.NoUpdatesAvailable.Text="Actualment no hi ha actualitzacions disponibles"
+Updater.FailedToLaunch="No s'han pogut executar l'actualitzador"
+Updater.GameCaptureActive.Title="Captura de joc activa"
+Updater.GameCaptureActive.Text="La llibreria de captura de jocs està actualment en ús. Tanqueu qualsevol joc/programa que estigui sent capturat (o reinicieu Windows) i proveu-ho de nou."
QuickTransitions.SwapScenes="Canvia la vista prèvia i sortida d'escenes després de la transició"
QuickTransitions.SwapScenesTT="Canvia la vista prèvia i sortida d'escenes després de la transició (si encara existeix l'escena original de la sortida). \nAixò no desfarà qualsevol canvi que pugui haver fet a l'escena original de la sortida."
QuickTransitions.DuplicateScene="Duplica l'escena"
-QuickTransitions.DuplicateSceneTT="Al editar la misma escena, permite la edición transformar/visibilidad de fuentes sin modificar las salida.\nPer editar les propietats de les fonts sense modificar la sortida, activi 'Duplicar Fonts'.\nCanviant aquest valor restablirà l'escena actual de sortida (si encara existeix)."
+QuickTransitions.DuplicateSceneTT="En editar la mateixa escena, permet editar la visibilitat i transformació de les fonts sense modificar la sortida.\nPer editar les propietats de les fonts sense modificar la sortida, activeu «Duplicar Fonts».\nSi canvieu aquest valor es restablirà l'escena actual de la sortida (si encara existeix)."
QuickTransitions.EditProperties="Duplica les fonts"
-QuickTransitions.EditPropertiesTT="En editar la mateixa escena, permeti editar propietats de fonts sense modificar la sortida.\n Això només es pot utilitzar si està activat 'Duplicar l'escena'.\nCertes fonts (tals com a fonts de captura o els mitjans de comunicació) no són compatibles amb això i no es poden editar per separat.\nCanviant aquest valor restablirà l'escena actual de sortida (si encara existeix).\n\nAdvertiment: com es duplicaran les fonts, això requerirà un extra de recursos del sistema i de vídeo."
+QuickTransitions.EditPropertiesTT="En editar la mateixa escena, permet editar les propietats de les fonts sense modificar la sortida.\nAixò només es pot utilitzar si s'ha activat «Duplicar l'escena».\nAlgunes fonts (com dispositius de captura o mèdia) no ho permeten i no es poden editar per separat.\nSi canvieu aquest valor es restablirà l'escena actual de la sortida (si encara existeix).\n\nAtenció: com que es duplicaran les fonts, poden ser necessaris més recursos del sistema o de vídeo."
QuickTransitions.HotkeyName="Transició Ràpida: %1"
Basic.AddTransition="Afegir transició configurable"
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Confirmeu la supressió"
ConfirmRemove.Text="Esteu segur que voleu suprimir «$1»?"
ConfirmRemove.TextMultiple="¿Segur que vols esborrar %1 elements?"
+Output.StartStreamFailed="No s'ha pogut iniciar la transmissió"
+Output.StartRecordingFailed="No s'ha pogut iniciar la gravació"
+Output.StartReplayFailed="No s'ha pogut iniciar la memòria intermèdia de reproducció"
+Output.StartFailedGeneric="Error en iniciar la sortida. Comproveu el registre per més detalls.\n\nAvís: Si utilitzeu els codificadors NVENC o AMD, assegureu-vos que els controladors de vídeo estan actualitzats."
+
Output.ConnectFail.Title="Error en connectar"
Output.ConnectFail.BadPath="Ruta o adreça URL no vàlida. Si us plau, comproveu la configuració per confirmar que són vàlids."
Output.ConnectFail.ConnectFailed="No ha pogut connectar al servidor"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Espai de disc insuficient"
Output.RecordNoSpace.Msg="No hi ha prou espai de disc per continuar la gravació."
Output.RecordError.Title="Error en l'enregistrament"
Output.RecordError.Msg="S'ha produït un error desconegut mentre es gravava."
+Output.ReplayBuffer.NoHotkey.Title="Cap tecla d'accés ràpid!"
+Output.ReplayBuffer.NoHotkey.Msg="Cap tecla d'accés ràpid establerta per la memòria intermèdia de reproducció. Configureu la tecla d'accés \"Desa\" per desar els enregistraments de reproducció."
Output.BadPath.Title="Ruta de l'arxiu incorrecta"
Output.BadPath.Text="La ruta configurada pel fitxer de sortida no és vàlida. Si us plau, comproveu la configuració per confirmar que s'ha creat una ruta de fitxer vàlida."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Camp superior primer"
Deinterlacing.BottomFieldFirst="Camp inferior primer"
+VolControl.SliderUnmuted="Control lliscant del volum per '%1': %2"
+VolControl.SliderMuted="Control lliscant del volum per '%1': %2 (silenciat)"
+VolControl.Mute="Silencia '%1'"
+VolControl.Properties="Propietats per '%1'"
+
Basic.Main.AddSceneDlg.Title="Afegeix una escena"
Basic.Main.AddSceneDlg.Text="Introduïu el nom de l'escena"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Escenes"
Basic.Main.Sources="Orígens"
Basic.Main.Connecting="S'està connectant..."
Basic.Main.StartRecording="Inicia l'enregistrament"
-Basic.Main.StartStreaming="Inicia l'enregistrament"
+Basic.Main.StartReplayBuffer="Inicia la reproducció de la memòria intermèdia"
+Basic.Main.StartStreaming="Inicia la transmissió"
Basic.Main.StopRecording="Atura l'enregistrament"
Basic.Main.StoppingRecording="Aturant l'enregistrament..."
+Basic.Main.StopReplayBuffer="Atura la reproducció de la memòria intermèdia"
+Basic.Main.StoppingReplayBuffer="S'està aturant la reproducció de la memòria intermèdia..."
Basic.Main.StopStreaming="Atura l'enregistrament"
Basic.Main.StoppingStreaming="Aturant la transmissió..."
Basic.Main.ForceStopStreaming="Atura l'enregistrament (descarta el retard)"
@@ -270,7 +305,7 @@ Basic.MainMenu.File.Export="&Exporta"
Basic.MainMenu.File.Import="&Importa"
Basic.MainMenu.File.ShowRecordings="Mostra els en®istraments"
Basic.MainMenu.File.Remux="Converteix format de gravacions"
-Basic.MainMenu.File.Settings="&Paràmetres"
+Basic.MainMenu.File.Settings="&Configuració"
Basic.MainMenu.File.ShowSettingsFolder="Mostrar carpeta de configuració"
Basic.MainMenu.File.ShowProfileFolder="Mostra la carpeta del perfil"
Basic.MainMenu.AlwaysOnTop="&Sempre al davant"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Refés"
Basic.MainMenu.Edit.UndoAction="&Desfés $1"
Basic.MainMenu.Edit.RedoAction="&Refés $1"
Basic.MainMenu.Edit.LockPreview="&Bloquejar vista prèvia"
+Basic.MainMenu.Edit.Scale="Vista prèvia i escalat"
+Basic.MainMenu.Edit.Scale.Window="Ajusta a la finestra"
+Basic.MainMenu.Edit.Scale.Canvas="Tela (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Sortida (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transforma"
Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformació..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Copia la transformació"
+Basic.MainMenu.Edit.Transform.PasteTransform="Enganxa la transformació"
Basic.MainMenu.Edit.Transform.ResetTransform="&Reinicialitza Transformació"
Basic.MainMenu.Edit.Transform.Rotate90CW="Gira 90 graus a la dreta"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Gira 90 graus a l'esquerra"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="Barra d'estat"
Basic.MainMenu.SceneCollection="&Col·lecció d'escenes"
Basic.MainMenu.Profile="&Perfil"
+Basic.MainMenu.Profile.Import="Importació del perfil"
+Basic.MainMenu.Profile.Export="Exportació del perfil"
+Basic.MainMenu.SceneCollection.Import="Importa col·lecció d'escenes"
+Basic.MainMenu.SceneCollection.Export="Exporta la col·lecció d'escenes"
+Basic.MainMenu.Profile.Exists="El perfil ja existeix"
+Basic.MainMenu.SceneCollection.Exists="La col·lecció d'escenes ja existeix"
Basic.MainMenu.Tools="&Eines"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Hi han canvis no desats. Voleu desar els canvis?"
Basic.Settings.General="General"
Basic.Settings.General.Theme="Tema"
Basic.Settings.General.Language="Llengua"
+Basic.Settings.General.EnableAutoUpdates="Comprova si hi ha actualitzacions automàticament a l'inici"
Basic.Settings.General.WarnBeforeStartingStream="Mostra diàleg de confirmació quan s'iniciï una transmissió"
Basic.Settings.General.WarnBeforeStoppingStream="Mostra diàleg de confirmació quan s'aturi una transmissió"
+Basic.Settings.General.Projectors="Projectors"
Basic.Settings.General.HideProjectorCursor="Amaga el cursor sobre projectors"
Basic.Settings.General.ProjectorAlwaysOnTop="Projectors sempre en la part superior"
Basic.Settings.General.Snapping="Ajustament d'alineació de la font"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Ajustar les fonts a altres fonts"
Basic.Settings.General.SnapDistance="Ajusta la sensibilitat"
Basic.Settings.General.RecordWhenStreaming="Enregistra automàticament quan es transmet"
Basic.Settings.General.KeepRecordingWhenStreamStops="Mantenir l'enregistrament quan s'atura la transmissió"
-Basic.Settings.General.SysTrayEnabled="Activar icona a la safata del sistema"
+Basic.Settings.General.ReplayBufferWhileStreaming="Inicia la reproducció de la memòria intermèdia automàticament durant la transmissió"
+Basic.Settings.General.KeepReplayBufferStreamStops="Mantén activa la memòria intermèdia de reproducció quan la transmissió s'aturi"
+Basic.Settings.General.SysTray="Safata del sistema"
Basic.Settings.General.SysTrayWhenStarted="Minimitzar a la safata del sistema en iniciar"
+Basic.Settings.General.SystemTrayHideMinimize="Minimitza sempre a la safata del sistema en lloc de la barra de tasques"
+Basic.Settings.General.SaveProjectors="Desa els projectors en sortir"
Basic.Settings.Stream="Directe"
Basic.Settings.Stream.StreamType="Tipus de directe"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Mode de sortida"
Basic.Settings.Output.Mode.Simple="Simple"
Basic.Settings.Output.Mode.Adv="Avançat"
Basic.Settings.Output.Mode.FFmpeg="Sortida FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Activa la reproducció de la memòria intermèdia"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Temps de reproducció màxim (segons)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Memòria màxima (MB)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Ús aproximat de memòria: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="No es pot estimar l'ús de memòria. Establiu el límit màxim de memòria."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Nota: Assegureu-vos d'establir una tecla d'accés ràpid per la memòria intermèdia de reproducció a la secció de tecles ràpides)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Prefix del nom del fitxer de la memòria intermèdia"
+Basic.Settings.Output.ReplayBuffer.Suffix="Sufix"
Basic.Settings.Output.Simple.SavePath="Camí d'enregistrament"
Basic.Settings.Output.Simple.RecordingQuality="Qualitat de l'enregistrament"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Mateixa que en directe"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Advertiment de qualitat sense
Basic.Settings.Output.Simple.Warn.MultipleQSV="Advertència: No es poden utilitzar diversos descodificadors QSV separats en transmetre i enregistrar al mateix temps. Per transmetre i engrestriar al mateix temps, si us plau modifiqueu-los, ja sigui el codificador de gravació o el codificador de transmissió."
Basic.Settings.Output.Simple.Encoder.Software="Programari (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Maquinari (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Maquinari (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Maquinari (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Programari (preconfiguració de x264 amb baix ús de CPU, augmenta la mida del fitxer)"
Basic.Settings.Output.VideoBitrate="Bitrate de vídeo"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Pista 1"
Basic.Settings.Output.Adv.Audio.Track2="Pista 2"
Basic.Settings.Output.Adv.Audio.Track3="Pista 3"
Basic.Settings.Output.Adv.Audio.Track4="Pista 4"
+Basic.Settings.Output.Adv.Audio.Track5="Pista 5"
+Basic.Settings.Output.Adv.Audio.Track6="Pista 6"
Basic.Settings.Output.Adv.Recording="Enregistrament"
Basic.Settings.Output.Adv.Recording.Type="Tipus"
@@ -417,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Configuració del codificador
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Codificador d'àudio"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Configuració de codificador d'àudio (si escau)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Configuració del convertidor (si escau)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Interval de fotogrames clau (fotogrames)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Mostra tots els codificadors (encara que siguin potencialment incompatibles)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="Espai de color YUV"
Basic.Settings.Advanced.Video.ColorRange="Gamma de color YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Parcial"
Basic.Settings.Advanced.Video.ColorRange.Full="Màxima"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Dispositiu de monitorització d'àudio"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Per defecte"
Basic.Settings.Advanced.StreamDelay="Retard del directe"
Basic.Settings.Advanced.StreamDelay.Duration="Durada (en segons)"
Basic.Settings.Advanced.StreamDelay.Preserve="Preservar el punt de tall (augmenta retard) quan s'estigui reconnectant"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Ús de memòria estimat: %1 MB"
Basic.Settings.Advanced.Network="Xarxa"
Basic.Settings.Advanced.Network.BindToIP="Enllaçar amb"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Activa el nou codi de xarxa"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Mode de baixa latència"
Basic.AdvAudio="&Propietats avançades d'àudio"
Basic.AdvAudio.Name="Nom"
@@ -483,19 +553,19 @@ Basic.AdvAudio.Volume="Volum (%)"
Basic.AdvAudio.Mono="Mescla a Mono"
Basic.AdvAudio.Panning="Balanç"
Basic.AdvAudio.SyncOffset="Correcció de sincronització (ms)"
+Basic.AdvAudio.Monitoring="Monitorització d'àudio"
+Basic.AdvAudio.Monitoring.None="Monitorització desactivada"
+Basic.AdvAudio.Monitoring.MonitorOnly="Només monitorizació (silencia la sortida)"
+Basic.AdvAudio.Monitoring.Both="Monitorització i sortida"
Basic.AdvAudio.AudioTracks="Pistes"
Basic.Settings.Hotkeys="Dreceres de teclat"
Basic.Settings.Hotkeys.Pair="Combinacions de tecles compartides amb '%1' actuen com a palanques"
-Basic.Hotkeys.StartStreaming="Inicia el directe"
-Basic.Hotkeys.StopStreaming="Atura el directe"
-Basic.Hotkeys.StartRecording="Inicia l'enregistrament"
-Basic.Hotkeys.StopRecording="Atura l'enregistrament"
Basic.Hotkeys.SelectScene="Canviar a escena"
Basic.SystemTray.Show="Mostra"
-Basic.SystemTray.Hide="Oculta"
+Basic.SystemTray.Hide="Amaga"
Basic.SystemTray.Message.Reconnecting="Desconnectat. Tornant a connectar..."
@@ -545,4 +615,5 @@ SceneItemHide="Amaga «%1»"
OutputWarnings.NoTracksSelected="Heu de seleccionar almenys una cançó"
OutputWarnings.MultiTrackRecording="Advertiment: Alguns formats (com FLV) no suporten múltiples cançons per gravació"
+OutputWarnings.MP4Recording="Advertència: Els enregistraments desats en MP4 seran irrecuperables si l'arxiu no va poder finalitzar (p.ex. com a resultat de BSODs, pèrdues de potència, etc.). Si voleu enregistrar diverses pistes d'àudio utilitzi MKV i multiplexeu l'enregistrament a MP4 després que acabi (Fitxer-> Multiplexació d'enregistraments)"
diff --git a/UI/data/locale/cs-CZ.ini b/UI/data/locale/cs-CZ.ini
index 3504259..838de27 100644
--- a/UI/data/locale/cs-CZ.ini
+++ b/UI/data/locale/cs-CZ.ini
@@ -49,6 +49,26 @@ Right="Vpravo"
Top="Nahoře"
Bottom="Dole"
Reset="Resetovat"
+Hours="Hodiny"
+Minutes="Minuty"
+Seconds="Vteřiny"
+Deprecated="Zastaralé"
+ReplayBuffer="Záznam do paměti"
+Import="Importovat"
+Export="Exportovat"
+
+Updater.Title="Aktualizace"
+Updater.Text="K dispozici je nová verze:"
+Updater.UpdateNow="Aktualizovat nyní"
+Updater.RemindMeLater="Upozornit později"
+Updater.Skip="Přeskočit verzi"
+Updater.Running.Title="Program je stále aktivní"
+Updater.Running.Text="Některé výstupy jsou stále aktivní, zastavte je, prosím, před další pokusem o aktualizaci"
+Updater.NoUpdatesAvailable.Title="Žádná aktualizace"
+Updater.NoUpdatesAvailable.Text="Není dostupná žádná novější verze"
+Updater.FailedToLaunch="Nepodařilo se spustit aktualizátor"
+Updater.GameCaptureActive.Title="Snímání hry"
+Updater.GameCaptureActive.Text="Knihovna pro snímání her je aktivní. Ukončete prosím všechny snímané hry/programy (nebo restartujte Windows) a zkuste to znovu."
QuickTransitions.SwapScenes="Prohodit scény náhledu a výstupu po přechodu"
QuickTransitions.SwapScenesTT="Prohodí scény náhledu a výstupu po přechodu (pokud originální výstupní scéna stále existuje).\nTato funkce nevrátí provedené změny, které byly provedeny v originální scéně výstupu."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Potvrzení odebrání"
ConfirmRemove.Text="Opravdu si přejete odebrat '$1'?"
ConfirmRemove.TextMultiple="Opravdu si přejete odebrat %1 položky ?"
+Output.StartStreamFailed="Chyba při spouštění vysílání"
+Output.StartRecordingFailed="Chyba při spouštění nahrávání"
+Output.StartReplayFailed="Chyba při spouštění nahrávání do paměti"
+Output.StartFailedGeneric="Nastala chyba při začátku nahrávání. Zkontrolujte, prosím, textový záznam pro další podrobnosti.\n\nPoznámka: Pokud používáte enkodér NVENC či AMD, zkontrolujte zda používáte aktuální verzi grafického ovladače."
+
Output.ConnectFail.Title="Spojení se nezdařilo"
Output.ConnectFail.BadPath="Chybná cesta nebo adresa připojení. Zkontrolujte, prosím, správnost svých nastavení."
Output.ConnectFail.ConnectFailed="K serveru se nepodařilo připojit"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Nedostatek místa na disku"
Output.RecordNoSpace.Msg="Pro pokračování nahrávání není dostatek místa na disku."
Output.RecordError.Title="Chyba při nahrávání"
Output.RecordError.Msg="Při nahrávání došlo k nespecifikované chybě."
+Output.ReplayBuffer.NoHotkey.Title="Nepřiřazena žádná klávesová zkratka!"
+Output.ReplayBuffer.NoHotkey.Msg="Není nastavena žádná klávesová zkratka pro uložení záznamu. Nastavte ji prosím, abyste jej mohli ukládat."
Output.BadPath.Title="Špatná cesta k souboru"
Output.BadPath.Text="Nastavená cesta k výstupnímu souboru je chybná. Zkontrolujte nastavení, zda není cesta špatně napsána."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Svrchní řádek dříve"
Deinterlacing.BottomFieldFirst="Spodní řádek dříve"
+VolControl.SliderUnmuted="Posuvník hlasitosti pro '%1': %2"
+VolControl.SliderMuted="Posuvník hlasitosti pro '%1': %2 (ztlumeno)"
+VolControl.Mute="Ztlumit '%1'"
+VolControl.Properties="Vlastnosti pro \"%1\""
+
Basic.Main.AddSceneDlg.Title="Přidat scénu"
Basic.Main.AddSceneDlg.Text="Prosím, zadejte jméno scény"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Scény"
Basic.Main.Sources="Zdroje"
Basic.Main.Connecting="Připojování..."
Basic.Main.StartRecording="Začít nahrávat"
+Basic.Main.StartReplayBuffer="Spustit záznam do paměti"
Basic.Main.StartStreaming="Začít vysílat"
Basic.Main.StopRecording="Zastavit nahrávání"
Basic.Main.StoppingRecording="Zastavuji nahrávání..."
+Basic.Main.StopReplayBuffer="Zastavit záznam do paměti"
+Basic.Main.StoppingReplayBuffer="Zastavuji záznam do paměti..."
Basic.Main.StopStreaming="Zastavit vysílání"
Basic.Main.StoppingStreaming="Zastavuji vysílání..."
Basic.Main.ForceStopStreaming="Zastavit vysání (bez zpoždění)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="Znovu (&R)"
Basic.MainMenu.Edit.UndoAction="Zpět $1 (&U)"
Basic.MainMenu.Edit.RedoAction="Znovu $1 (&R)"
Basic.MainMenu.Edit.LockPreview="Uzamknout náh&led"
+Basic.MainMenu.Edit.Scale="Škálování náhledu (&S)"
+Basic.MainMenu.Edit.Scale.Window="Škálovat na okno"
+Basic.MainMenu.Edit.Scale.Canvas="Editor (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Výstup (%1x%2)"
Basic.MainMenu.Edit.Transform="Pozicování (&T)"
Basic.MainMenu.Edit.Transform.EditTransform="Upravit pozici... (&E)"
+Basic.MainMenu.Edit.Transform.CopyTransform="Kopírovat transformaci"
+Basic.MainMenu.Edit.Transform.PasteTransform="Vložit transformaci"
Basic.MainMenu.Edit.Transform.ResetTransform="Obnovit pozici (&R)"
Basic.MainMenu.Edit.Transform.Rotate90CW="Otočit o 90 stupňů vpravo"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Otočit o 90 stupňů vlevo"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Stavový řádek"
Basic.MainMenu.SceneCollection="Kolekce &scén"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Importovat profil"
+Basic.MainMenu.Profile.Export="Exportovat profil"
+Basic.MainMenu.SceneCollection.Import="Importovat kolekci scén"
+Basic.MainMenu.SceneCollection.Export="Exportovat kolekci scén"
+Basic.MainMenu.Profile.Exists="Tento profil již existuje"
+Basic.MainMenu.SceneCollection.Exists="Tato kolekce scén již existuje"
Basic.MainMenu.Tools="Nás&troje"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Některé změny nejsou uložené. Chcete je uložit nyn
Basic.Settings.General="Hlavní"
Basic.Settings.General.Theme="Vzhled"
Basic.Settings.General.Language="Jazyk"
+Basic.Settings.General.EnableAutoUpdates="Automaticky kontrolovat aktualizace při spuštění"
Basic.Settings.General.WarnBeforeStartingStream="Vyžadovat potvrzení pro spuštění vysílání"
Basic.Settings.General.WarnBeforeStoppingStream="Vyžadovat potvrzení pro ukončení vysílání"
+Basic.Settings.General.Projectors="Projektory"
Basic.Settings.General.HideProjectorCursor="Skrýt kurzor přes projektor"
Basic.Settings.General.ProjectorAlwaysOnTop="Zobrazovat projektor vždy navrchu"
Basic.Settings.General.Snapping="Přichycování zdrojů"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Přichytávat zdroje k ostatním zdrojům
Basic.Settings.General.SnapDistance="Citlivost přichycení"
Basic.Settings.General.RecordWhenStreaming="Automaticky nahrávat při vysílání"
Basic.Settings.General.KeepRecordingWhenStreamStops="Pokračovat v nahrávání i po zastavení vysílání"
-Basic.Settings.General.SysTrayEnabled="Zobrazit ikonu v oznamovací oblasti"
+Basic.Settings.General.ReplayBufferWhileStreaming="Automaticky zapnout záznam do paměti se začátkem vysílání"
+Basic.Settings.General.KeepReplayBufferStreamStops="Ponechat záznam do paměti aktivní i po ukončení vysílání"
+Basic.Settings.General.SysTray="Systémová lišta"
Basic.Settings.General.SysTrayWhenStarted="Minimalizovat do systémové lišty při spuštění"
+Basic.Settings.General.SystemTrayHideMinimize="Vždy minimalizovat do systémové lišty místo hlavního panelu"
+Basic.Settings.General.SaveProjectors="Při ukončení uložit projektory"
Basic.Settings.Stream="Vysílání"
Basic.Settings.Stream.StreamType="Typ vysílání"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Režim výstupu"
Basic.Settings.Output.Mode.Simple="Jednoduché"
Basic.Settings.Output.Mode.Adv="Rozšířené"
Basic.Settings.Output.Mode.FFmpeg="Výstup FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Povolit záznam od paměti"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximální čas záznamu (s)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximální využití paměti (MB)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Přibližné využití paměti: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nedokáži odhadnout využití paměti. Nastavte, prosím, maximální využití paměti."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Poznámka: Nezapomeňte si nastavit klávesovou zkratku pro tuto funkci)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Přípona souboru záznamu do paměti"
+Basic.Settings.Output.ReplayBuffer.Suffix="Přípona"
Basic.Settings.Output.Simple.SavePath="Cesta pro nahrávání"
Basic.Settings.Output.Simple.RecordingQuality="Nahrávací kvalita"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Stejná jako vysílaná"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Varování nastavené kvality!
Basic.Settings.Output.Simple.Warn.MultipleQSV="Varování: Není možné použit více oddělených QSV enkodérů pro streamování a nahrávání ve stejnou dobu. Pokud chcete tuto limitaci obejít, tak změňte použitý enkodér pro streamování či nahrávání."
Basic.Settings.Output.Simple.Encoder.Software="Softwarový (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardwarový (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardwarový (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardwarový (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Softwarový (x264 předvolba nízkého zatížení CPU, větší soubory)"
Basic.Settings.Output.VideoBitrate="Bitrate videa"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Stopa 1"
Basic.Settings.Output.Adv.Audio.Track2="Stopa 2"
Basic.Settings.Output.Adv.Audio.Track3="Stopa 3"
Basic.Settings.Output.Adv.Audio.Track4="Stopa 4"
+Basic.Settings.Output.Adv.Audio.Track5="Stopa 5"
+Basic.Settings.Output.Adv.Audio.Track6="Stopa 6"
Basic.Settings.Output.Adv.Recording="Nahrávání"
Basic.Settings.Output.Adv.Recording.Type="Typ"
@@ -417,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Nastavení enkodéru obrazu (
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Enkodér zvuku"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Nastavení enkodéru zvuku (pokud existuje)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Nastavení směšovače (pokud existuje)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Interval klíčových snímků (snímky)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Zobrazit všechny kodeky (i když je možné, že nejsou kompatibilní)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="Barevný prostor YUV"
Basic.Settings.Advanced.Video.ColorRange="Oblast barev YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Částečné"
Basic.Settings.Advanced.Video.ColorRange.Full="Plné"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Zařízení pro monitorování zvuku"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Výchozí"
Basic.Settings.Advanced.StreamDelay="Zpoždění vysílání"
Basic.Settings.Advanced.StreamDelay.Duration="Délka (vteřiny)"
Basic.Settings.Advanced.StreamDelay.Preserve="Zachovat zpoždění při obnovení spojení (zvýšení zpoždění)"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Přibližné využití paměti: %1 MB"
Basic.Settings.Advanced.Network="Síť"
Basic.Settings.Advanced.Network.BindToIP="Svázat s adresou"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Použít nový síťový kód"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Režim nízké odezvy"
Basic.AdvAudio="Rozšířené vlastnosti zvuku"
Basic.AdvAudio.Name="Název"
@@ -483,15 +553,15 @@ Basic.AdvAudio.Volume="Hlasitost (%)"
Basic.AdvAudio.Mono="Převést na Mono"
Basic.AdvAudio.Panning="Pozicování"
Basic.AdvAudio.SyncOffset="Zpoždění synchronizace (ms)"
+Basic.AdvAudio.Monitoring="Monitorování zvuku"
+Basic.AdvAudio.Monitoring.None="Monitorování vypnuto"
+Basic.AdvAudio.Monitoring.MonitorOnly="Pouhé monitorování (ztlumit výstup)"
+Basic.AdvAudio.Monitoring.Both="Monitorovat a odesílat na výstup"
Basic.AdvAudio.AudioTracks="Stopy"
Basic.Settings.Hotkeys="Zkratky"
Basic.Settings.Hotkeys.Pair="Kombinace kláves je sdílená s '%1' funguje jako přepínač"
-Basic.Hotkeys.StartStreaming="Začít vysílat"
-Basic.Hotkeys.StopStreaming="Zastavit vysílání"
-Basic.Hotkeys.StartRecording="Začít nahrávat"
-Basic.Hotkeys.StopRecording="Zastavit nahrávání"
Basic.Hotkeys.SelectScene="Přepnout na scénu"
Basic.SystemTray.Show="Zobrazit"
@@ -545,4 +615,5 @@ SceneItemHide="Skrýt '%1'"
OutputWarnings.NoTracksSelected="Musíte vybrat alespoň jednu stopu"
OutputWarnings.MultiTrackRecording="Varování: Některé formáty (např. FLV) nepodporují více zvukových stop na nahrávku"
+OutputWarnings.MP4Recording="Varování: Nahrávky uložené v MP4 nebude možné obnovit, pokud soubor nemohl být dokončen (např. po BSOD, výpadku napájení atp.). Pokud chcete nahrávat více zvukových stop, promyslete použití MKV a poté převodení do MP4 (Soubor -> Převést nahrávky)"
diff --git a/UI/data/locale/da-DK.ini b/UI/data/locale/da-DK.ini
index 251a738..097e923 100644
--- a/UI/data/locale/da-DK.ini
+++ b/UI/data/locale/da-DK.ini
@@ -4,11 +4,11 @@ Region="Danmark"
OK="OK"
Apply="Anvend"
-Cancel="Annuller"
+Cancel="Annullér"
Close="Luk"
Save="Gem"
Discard="Kassér"
-Disable="Deaktiver"
+Disable="Deaktivér"
Yes="Ja"
No="Nej"
Add="Tilføj"
@@ -27,10 +27,10 @@ Mixer="Mixer"
Browse="Browse"
Mono="Mono"
Stereo="Stereo"
-DroppedFrames="Taber frames %1 (%2%)"
-PreviewProjector="Fuldskærms projektering (forhåndsvisning)"
-SceneProjector="Fuldskærms projektering (scene)"
-SourceProjector="Fuldskærms projektering (kilde)"
+DroppedFrames="Tabte frames %1 (%2%)"
+PreviewProjector="Fuldskærmsprojektering (forhåndsvisning)"
+SceneProjector="Fuldskærmsprojektering (scene)"
+SourceProjector="Fuldskærmsprojektering (kilde)"
Clear="Ryd"
Revert="Gendan"
Show="Vis"
@@ -49,10 +49,33 @@ Right="Højre"
Top="Top"
Bottom="Bund"
Reset="Nulstil"
+Hours="Timer"
+Minutes="Minutter"
+Seconds="Sekunder"
+Deprecated="Ophørt"
+ReplayBuffer="Genafspilningsbuffer"
+Import="Importér"
+Export="Eksportér"
+
+Updater.Title="Ny opdatering tilgængelig"
+Updater.Text="Der er en ny opdatering tilgængelig:"
+Updater.UpdateNow="Opdater nu"
+Updater.RemindMeLater="Påmind mig senere"
+Updater.Skip="Spring versionen over"
+Updater.Running.Title="Program er aktivt i øjeblikket"
+Updater.Running.Text="Outputs er aktive i øjeblikket. Luk venligst alle aktive outputs før forsøg på opdatering"
+Updater.NoUpdatesAvailable.Title="Ingen opdateringer tilgængelige"
+Updater.NoUpdatesAvailable.Text="Ingen opdateringer er tilgængelige i øjeblikket"
+Updater.FailedToLaunch="Kunne ikke starte opdatering"
+Updater.GameCaptureActive.Title="Spil capture aktiv"
+Updater.GameCaptureActive.Text="Spil capture fangstbibliotek er i brug i øjeblikket. Luk venligst alle spil/programmer der bliver captured (eller genstart windows) og prøv igen."
QuickTransitions.SwapScenes="Byt om på forhåndsvisning/output scener efter overgang"
+QuickTransitions.SwapScenesTT="Ombytter uddrag- og output-scener efter omskiftning (hvis oprindelige output-scene stadig eksisterer).\nDette vil ikke omgøre eventuelle ændringer, der måtte været udført på den oprindelige output-scene."
QuickTransitions.DuplicateScene="Dupliker scene"
+QuickTransitions.DuplicateSceneTT="Muliggør, ved redigere af den samme, scene, redigering af transformering/synlighed af kilder uden at ændre på output. \nFor at rediger egenskaber for kilder uden at ændre på output, aktivér 'Duplikér Kilder'.\nÆndring af denne værd vil nulstille den nuværende output-scene (hvis den stadig findes)."
QuickTransitions.EditProperties="Dupliker kilder"
+QuickTransitions.EditPropertiesTT="Muliggør, ved redigering af den samme scene, redigering af egenskaber for kilder uden at ændre på output.\nDette kan kun benyttes, hvis 'Duplikér Scene' er aktiv. \nVisse kilder (såsom optagne kilder eller mediekilder) understøtter ikke dette og kan ikke redigeres separat.\nÆndring af denne værdi vil nulstille den nuværende output-scene (hvis den stadig findes).\n\nAdvarsel: Da kilder vil blive duplikeret, kan dette kræve ekstra system- eller videoressourcer."
QuickTransitions.HotkeyName="Hurtig overgang: %1"
Basic.AddTransition="Tilføj konfigurerbar overgang"
@@ -85,6 +108,12 @@ ConfirmExit.Text="OBS er aktiv i øjeblikket. Alle streams/optagelser vil blive
ConfirmRemove.Title="Bekræfte fjern"
ConfirmRemove.Text="Er du sikker på du ønsker at fjerne '$1'?"
+ConfirmRemove.TextMultiple="Er du sikker på at du vil fjerne %1 elementer?"
+
+Output.StartStreamFailed="Kunne ikke starte streaming"
+Output.StartRecordingFailed="Kunne ikke begynde optagelsen"
+Output.StartReplayFailed="Kunne ikke starte replay buffer"
+Output.StartFailedGeneric="Start af output mislykkedes. Kontroller venligst loggen for oplysninger.\n\nBemærk: Hvis du bruger NVENC eller AMD encoder, så sørg for at dine video drivere er opdateret."
Output.ConnectFail.Title="Kunne ikke oprette forbindelse"
Output.ConnectFail.BadPath="Ugyldig sti eller forbindelses URL. Kontroller indstillinger for at bekræfte, at de er gyldige."
@@ -99,6 +128,8 @@ Output.RecordNoSpace.Title="Utilstrækkelig diskplads"
Output.RecordNoSpace.Msg="Der er ikke tilstrækkelig diskplads til at fortsætte optagelsen."
Output.RecordError.Title="Optagelsesfejl"
Output.RecordError.Msg="Der opstod en uangivet fejl under optagelsen."
+Output.ReplayBuffer.NoHotkey.Title="Ingen genvejstast sat!"
+Output.ReplayBuffer.NoHotkey.Msg="Ingen Gem-genvejstast sat til genafspilningsbuffer. Sæt venligst \"Gem\"-genvejstasten til brug for at gemme genafspilningsoptagelser."
Output.BadPath.Title="Dårlig filsti"
Output.BadPath.Text="Den konfigureret output sti er ugyldig. Kontroller indstillinger for at bekræfte, at en gyldig filsti er angivet."
@@ -116,6 +147,7 @@ LicenseAgreement.Exit="Afslut"
Remux.SourceFile="OBS optagelse"
Remux.TargetFile="Destinationsfil"
Remux.Remux="Remux"
+Remux.OBSRecording="OBS optagelse"
Remux.FinishedTitle="Remuxing færdigt"
Remux.Finished="Optagelse remuxed"
Remux.FinishedError="Optagelse remuxed, men filen kan være ufuldstændige"
@@ -129,8 +161,8 @@ Remux.ExitUnfinished="Remuxing er ikke færdig. Hvis du stopper nu, kan du gøre
UpdateAvailable="Ny opdatering tilgængelig"
UpdateAvailable.Text="Version %1.%2.%3 er nu tilgængelig. Klik her for at downloade "
-Basic.DesktopDevice1="Desktop lyd"
-Basic.DesktopDevice2="Desktop lyd 2"
+Basic.DesktopDevice1="Skrivebordslyd"
+Basic.DesktopDevice2="Skrivebordslyd 2"
Basic.AuxDevice1="Mic/Aux"
Basic.AuxDevice2="Mic/Aux 2"
Basic.AuxDevice3="Mic/Aux 3"
@@ -141,12 +173,28 @@ Basic.DisplayCapture="Indfang display"
Basic.Main.PreviewConextMenu.Enable="Aktiver visning"
+ScaleFiltering="Skala filtrering"
+ScaleFiltering.Point="Punkt"
+ScaleFiltering.Bilinear="Bilinear"
+ScaleFiltering.Bicubic="Bikubisk"
+ScaleFiltering.Lanczos="Lanczos"
Deinterlacing="Deinterlacing"
Deinterlacing.Discard="Kassér"
Deinterlacing.Retro="Retro"
+Deinterlacing.Blend="Bland"
+Deinterlacing.Blend2x="Blend 2x"
Deinterlacing.Linear="Lineær"
Deinterlacing.Linear2x="Lineær 2x"
+Deinterlacing.Yadif="Yadif"
+Deinterlacing.Yadif2x="Yadif 2x"
+Deinterlacing.TopFieldFirst="Øverste felt først"
+Deinterlacing.BottomFieldFirst="Nederste felt først"
+
+VolControl.SliderUnmuted="Lydstyrkeskyder for '%1': %2"
+VolControl.SliderMuted="Lydstyrkeskyder for '%1': %2 (lyd i øjeblikket slået fra)"
+VolControl.Mute="Gør '%1' tavs"
+VolControl.Properties="Egenskaber for '%1'"
Basic.Main.AddSceneDlg.Title="Tilføje scene"
Basic.Main.AddSceneDlg.Text="Angiv navnet på scene"
@@ -178,7 +226,9 @@ Basic.PropertiesWindow.ConfirmTitle="Indstillinger ændret"
Basic.PropertiesWindow.Confirm="Der er ændringer, som ikke er gemt. Vil du gerne beholde dem?"
Basic.PropertiesWindow.NoProperties="Ingen egenskaber tilgængelige"
Basic.PropertiesWindow.AddFiles="Tilføj filer"
+Basic.PropertiesWindow.AddDir="Tilføj mappe"
Basic.PropertiesWindow.AddURL="Tilføj sti/url"
+Basic.PropertiesWindow.AddEditableListDir="Tilføj mappe til '%1'"
Basic.PropertiesWindow.AddEditableListFiles="Tilføj filer til '%1'"
Basic.PropertiesWindow.AddEditableListEntry="Tilføj emne til '%1'"
Basic.PropertiesWindow.EditEditableListEntry="Rediger emne fra '%1'"
@@ -240,9 +290,14 @@ Basic.Main.Scenes="Scener"
Basic.Main.Sources="Kilder"
Basic.Main.Connecting="Forbinder..."
Basic.Main.StartRecording="Start optagelse"
+Basic.Main.StartReplayBuffer="Start Genafspilningsbuffer"
Basic.Main.StartStreaming="Start streaming"
Basic.Main.StopRecording="Stop optagelse"
+Basic.Main.StoppingRecording="Stopper optagelse..."
+Basic.Main.StopReplayBuffer="Stop Genafspilningsbuffer"
+Basic.Main.StoppingReplayBuffer="Stopper Genafspilningsbuffer..."
Basic.Main.StopStreaming="Stop streaming"
+Basic.Main.StoppingStreaming="Stopper stream..."
Basic.Main.ForceStopStreaming="Stop streaming (ignorer forsinkelse)"
Basic.MainMenu.File="&Fil"
@@ -261,8 +316,15 @@ Basic.MainMenu.Edit.Undo="Fortryd (&U)"
Basic.MainMenu.Edit.Redo="&Redo"
Basic.MainMenu.Edit.UndoAction="Fortryd $1 (&U)"
Basic.MainMenu.Edit.RedoAction="&Redo $1"
+Basic.MainMenu.Edit.LockPreview="&Lås forhåndsvisning"
+Basic.MainMenu.Edit.Scale="Forhåndsvisning & Skalering"
+Basic.MainMenu.Edit.Scale.Window="Skalér til vindue"
+Basic.MainMenu.Edit.Scale.Canvas="Lærred (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Output (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformering"
-Basic.MainMenu.Edit.Transform.EditTransform="Redigere transformering... (&E)"
+Basic.MainMenu.Edit.Transform.EditTransform="Rediger transformering... (&E)"
+Basic.MainMenu.Edit.Transform.CopyTransform="Kopiér transformation"
+Basic.MainMenu.Edit.Transform.PasteTransform="Indsæt transformation"
Basic.MainMenu.Edit.Transform.ResetTransform="Nulstille transformering (&R)"
Basic.MainMenu.Edit.Transform.Rotate90CW="Roter 90 grader CW"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Roter 90 grader CCW"
@@ -275,14 +337,26 @@ Basic.MainMenu.Edit.Transform.CenterToScreen="&Center til skærm"
Basic.MainMenu.Edit.Order="Rækkefølge (&O)"
Basic.MainMenu.Edit.Order.MoveUp="Flyt Op (&U)"
Basic.MainMenu.Edit.Order.MoveDown="Flyt Ned (&D)"
-Basic.MainMenu.Edit.Order.MoveToTop="Flyt til &Toppen"
+Basic.MainMenu.Edit.Order.MoveToTop="Flyt til &toppen"
Basic.MainMenu.Edit.Order.MoveToBottom="Flyt til &Bunden"
Basic.MainMenu.Edit.AdvAudio="&Avancerede lydegenskaber"
+Basic.MainMenu.View="&Vis"
+Basic.MainMenu.View.Toolbars="&Værktøjslinjer"
+Basic.MainMenu.View.Toolbars.Listboxes="&Listebokse"
+Basic.MainMenu.View.SceneTransitions="S&cene overgange"
+Basic.MainMenu.View.StatusBar="&Statuslinje"
Basic.MainMenu.SceneCollection="&Scenesamling"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Importér profil"
+Basic.MainMenu.Profile.Export="Eksportér profil"
+Basic.MainMenu.SceneCollection.Import="Importér scenesamling"
+Basic.MainMenu.SceneCollection.Export="Eksportér scenesamling"
+Basic.MainMenu.Profile.Exists="Profilen findes allerede"
+Basic.MainMenu.SceneCollection.Exists="Scenesamlingen findes allerede"
+Basic.MainMenu.Tools="Værk&tøjer"
Basic.MainMenu.Help="&Hjælp"
Basic.MainMenu.Help.Website="Besøg &websted"
@@ -300,13 +374,25 @@ Basic.Settings.Confirm="Du har ugemte ændringer. Skal ændringerne gemmes?"
Basic.Settings.General="Generelt"
Basic.Settings.General.Theme="Tema"
Basic.Settings.General.Language="Sprog"
+Basic.Settings.General.EnableAutoUpdates="Automatisk søgning efter opdateringer ved opstart"
Basic.Settings.General.WarnBeforeStartingStream="Vis bekræftelses-dialog ved opstart af stream"
Basic.Settings.General.WarnBeforeStoppingStream="Vis bekræftelses-dialog ved afslutning af stream"
+Basic.Settings.General.Projectors="Projektorer"
+Basic.Settings.General.HideProjectorCursor="Skjul markør over projektorer"
+Basic.Settings.General.ProjectorAlwaysOnTop="Hav altid projektorer øverst"
Basic.Settings.General.Snapping="Kilde justeringsfastgørelse"
Basic.Settings.General.ScreenSnapping="Fastgør kilder til kanten af skærmen"
Basic.Settings.General.CenterSnapping="Fastgør kilder til horisontalt og vertikalt centrum"
Basic.Settings.General.SourceSnapping="Fastgør kilder til andre kilder"
Basic.Settings.General.SnapDistance="Fastgørings-følsomhed"
+Basic.Settings.General.RecordWhenStreaming="Optag automatisk ved streaming"
+Basic.Settings.General.KeepRecordingWhenStreamStops="Bliv ved med at optage når stream stopper"
+Basic.Settings.General.ReplayBufferWhileStreaming="Start automatisk replay buffer ved streaming"
+Basic.Settings.General.KeepReplayBufferStreamStops="Hold replay buffer aktiv når stream stopper"
+Basic.Settings.General.SysTray="Processlinjen"
+Basic.Settings.General.SysTrayWhenStarted="Minimer til proceslinjen ved start"
+Basic.Settings.General.SystemTrayHideMinimize="Minimer altid til processlinjen i stedet for værktøjslinjen"
+Basic.Settings.General.SaveProjectors="Gem projektorer ved afslutning"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Streamtype"
@@ -321,21 +407,41 @@ Basic.Settings.Output.Mode="Output tilstand"
Basic.Settings.Output.Mode.Simple="Simpel"
Basic.Settings.Output.Mode.Adv="Avanceret"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg output"
+Basic.Settings.Output.UseReplayBuffer="Aktivér Genafspilningsbuffer"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maksimal genafspilningstid (sek.)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maksimal hukommelse (MB)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Anslået hukommelsesforbrug: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Ikke kan beregne hukommelsesforbrug. Sæt venligst maks. hukommelsesgrænse."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Bemærk: Sørg for at sætte en genvejstast til genafspilningsbufferen i sektionen for genvejstaster)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Genafspilningsbuffer filnavn præfiks"
+Basic.Settings.Output.ReplayBuffer.Suffix="Endelse"
Basic.Settings.Output.Simple.SavePath="Optagelsessti"
Basic.Settings.Output.Simple.RecordingQuality="Optagelseskvalitet"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Samme som stream"
Basic.Settings.Output.Simple.RecordingQuality.Small="Høj kvalitet, medium filstørrelse"
Basic.Settings.Output.Simple.RecordingQuality.HQ="Samme kvalitet, stor filstørrelse"
Basic.Settings.Output.Simple.RecordingQuality.Lossless="Tabsfri kvalitet, utrolig stor filstørrelse"
+Basic.Settings.Output.Simple.Warn.VideoBitrate="Advarsel: Video-streaming bitraten sættes til %1, som er den øvre grænse for den aktuelle streaming-tjeneste. Er du sikker på, at du vil at gå over %1, så aktivér venligst avancerede valg for encoder og afmarkér \"Gennemtving streaming-tjenestes bitratebegrænsninger\"."
+Basic.Settings.Output.Simple.Warn.AudioBitrate="Advarsel: Audio-streaming bitraten sættes til %1, som er den øvre grænse for den aktuelle streaming-tjeneste. Er du sikker på, at du vil at gå over %1, så aktivér venligst avancerede valg for encoder og afmarkér \"Gennemtving streaming-tjenestes bitratebegrænsninger\"."
+Basic.Settings.Output.Simple.Warn.Encoder="Advarsel: Optagelse med en software-encoder i en anden kvalitet end det streamede vil medføre ekstra CPU-forbrug, hvis du streamer og optager samtidigt."
+Basic.Settings.Output.Simple.Warn.Lossless="Advarsel: Tabsfri kvalitet genererer gevaldigt store filstørrelser! Tabsfri kvalitet kan bruge op til 7 GB diskplads pr. minut ved høje opløsninger og billedhastigheder. Tabsfri tilstand anbefales ikke til lange optagelser, medmindre du har en meget stor mængde tilgængelig diskplads."
+Basic.Settings.Output.Simple.Warn.Lossless.Msg="Sikker på, at du vil benytte tabsfri kvalitet?"
+Basic.Settings.Output.Simple.Warn.Lossless.Title="Tabsfri kvalitet-advarsel!"
+Basic.Settings.Output.Simple.Warn.MultipleQSV="Advarsel: Du kan ikke benytte flere særskilte QSV-encoders ved streaming og optagelse på samme tid. Ønsker du at streame og optage samtidig, bedes du ændre enten optagelses- eller stream-encoder."
Basic.Settings.Output.Simple.Encoder.Software="Software (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)"
+Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 lav, forudindstillet CPU-forbrug, øger filstørrelsen)"
Basic.Settings.Output.VideoBitrate="Video Bitrate"
Basic.Settings.Output.AudioBitrate="Audio Bitrate"
Basic.Settings.Output.Reconnect="Automatisk Reconnect"
Basic.Settings.Output.RetryDelay="Retry forsinkelse (sekunder)"
Basic.Settings.Output.MaxRetries="Maksimum forsøg"
Basic.Settings.Output.Advanced="Aktiver avancerede Encoder indstillinger"
+Basic.Settings.Output.EncoderPreset="Encoder forudindstilling (hurtigere= mindre CPU-kraft)"
+Basic.Settings.Output.CustomEncoderSettings="Tilpasset Encoder-indstillinger"
+Basic.Settings.Output.CustomMuxerSettings="Tilpasset Muxer-indstillinger"
Basic.Settings.Output.NoSpaceFileName="Opret filnavne uden mellemrum"
Basic.Settings.Output.Adv.Rescale="Om-skalere output"
@@ -346,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Spor 1"
Basic.Settings.Output.Adv.Audio.Track2="Spor 2"
Basic.Settings.Output.Adv.Audio.Track3="Spor 3"
Basic.Settings.Output.Adv.Audio.Track4="Spor 4"
+Basic.Settings.Output.Adv.Audio.Track5="Sport 5"
+Basic.Settings.Output.Adv.Audio.Track6="Spor 6"
Basic.Settings.Output.Adv.Recording="Optagelse"
Basic.Settings.Output.Adv.Recording.Type="Type"
@@ -357,12 +465,15 @@ Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Overskriv hvis filen eksi
Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg outputtype"
Basic.Settings.Output.Adv.FFmpeg.Type.URL="Output til URL"
Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Output til fil"
+Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="Almindelige optagelsesformater"
Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Alle filer"
Basic.Settings.Output.Adv.FFmpeg.SavePathURL="Filsti eller URL"
Basic.Settings.Output.Adv.FFmpeg.Format="Containerformat"
Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Lyd"
Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Video"
Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Standard format"
+Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Container-format beskrivelse"
+Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Lyd/Video-codec gættet fra filsti eller URL"
Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Standard encoder"
Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Deaktiver encoder"
Basic.Settings.Output.Adv.FFmpeg.VEncoder="Video encoder"
@@ -370,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Video encoder indstillinger (
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Lyd encoder"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Lyd encoder indstillinger (hvis nogen)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer indstillinger (hvis nogen)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Keyframe-Interval (billeder)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Vis alle codecs (selv potentielt inkompatible)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -399,40 +512,62 @@ Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (Skarp skalering, 32 prøv
Basic.Settings.Audio="Lyd"
Basic.Settings.Audio.SampleRate="Sample Rate"
Basic.Settings.Audio.Channels="Kanaler"
-Basic.Settings.Audio.DesktopDevice="Desktop lydenhed"
-Basic.Settings.Audio.DesktopDevice2="Desktop lydenhed 2"
+Basic.Settings.Audio.DesktopDevice="Skrivebord lydenhed"
+Basic.Settings.Audio.DesktopDevice2="Skrivebord lydenhed 2"
Basic.Settings.Audio.AuxDevice="Mic/Auxiliary lydenhed"
Basic.Settings.Audio.AuxDevice2="Mic/Auxiliary lydenhed 2"
Basic.Settings.Audio.AuxDevice3="Mic/Auxiliary lydenhed 3"
Basic.Settings.Audio.EnablePushToMute="Aktiver tryk-for-stilhed"
+Basic.Settings.Audio.PushToMuteDelay="Tryk for at gøre tavs-forsinkelse"
Basic.Settings.Audio.EnablePushToTalk="Aktiver tryk-for-tale"
+Basic.Settings.Audio.PushToTalkDelay="Tryk for at gøre hørbar-forsinkelse"
Basic.Settings.Audio.UnknownAudioDevice="[Enhed ikke tilsluttet eller ikke tilgængelig]"
Basic.Settings.Advanced="Avanceret"
+Basic.Settings.Advanced.General.ProcessPriority="Proces prioritet"
+Basic.Settings.Advanced.General.ProcessPriority.High="Høj"
+Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Over normal"
+Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal"
+Basic.Settings.Advanced.General.ProcessPriority.Idle="Ikke aktiv"
+Basic.Settings.Advanced.FormatWarning="Advarsel: Farveformater ud over NV12 er primært beregnet til optagelse, og de anbefales ikke under streaming. Streaming kan medføre øget CPU-forbrug grundet farveformatkonvertering."
+Basic.Settings.Advanced.Audio.BufferingTime="Lyd-bufferinterval"
Basic.Settings.Advanced.Video.ColorFormat="Farveformat"
Basic.Settings.Advanced.Video.ColorSpace="YUV farverum"
Basic.Settings.Advanced.Video.ColorRange="YUV farveområde"
Basic.Settings.Advanced.Video.ColorRange.Partial="Delvis"
Basic.Settings.Advanced.Video.ColorRange.Full="Fuld"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Lyd overvågningsenhed"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Standard"
Basic.Settings.Advanced.StreamDelay="Stream forsinkelse"
Basic.Settings.Advanced.StreamDelay.Duration="Varighed (sekunder)"
+Basic.Settings.Advanced.StreamDelay.Preserve="Bevar afskæringspunkt (forøg forsinkelse) ved forbindelsesgendannelse"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Anslået hukommelsesbrug: %1 MB"
+Basic.Settings.Advanced.Network="Netværk"
+Basic.Settings.Advanced.Network.BindToIP="Bind til IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Aktivér ny netværkskode"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Lav forsinkelsestilstand"
Basic.AdvAudio="Avancerede lydegenskaber"
Basic.AdvAudio.Name="Navn"
Basic.AdvAudio.Volume="Volumen (%)"
+Basic.AdvAudio.Mono="Nedmix til Mono"
Basic.AdvAudio.Panning="Panorering"
+Basic.AdvAudio.SyncOffset="Synkr-forskydning (ms)"
+Basic.AdvAudio.Monitoring="Lydovervågning"
+Basic.AdvAudio.Monitoring.None="Overvågning fra"
+Basic.AdvAudio.Monitoring.MonitorOnly="Kun overvågning (mute output)"
+Basic.AdvAudio.Monitoring.Both="Overvåg og output"
Basic.AdvAudio.AudioTracks="Spor"
Basic.Settings.Hotkeys="Genvejstaster"
+Basic.Settings.Hotkeys.Pair="Tastekombinationer delt med '%1' fungerer som omskiftere"
-Basic.Hotkeys.StartStreaming="Start streaming"
-Basic.Hotkeys.StopStreaming="Stop streaming"
-Basic.Hotkeys.StartRecording="Start optagelse"
-Basic.Hotkeys.StopRecording="Stop optagelse"
Basic.Hotkeys.SelectScene="Skift til scene"
+Basic.SystemTray.Show="Vis"
+Basic.SystemTray.Hide="Skjul"
+Basic.SystemTray.Message.Reconnecting="Afbrudt. Forbinder igen..."
Hotkeys.Insert="Insert"
Hotkeys.Delete="Delete"
@@ -478,4 +613,7 @@ Push-to-talk="Tryk-for-tale"
SceneItemShow="Vis '%1'"
SceneItemHide="Skjul '%1'"
+OutputWarnings.NoTracksSelected="Du skal vælge minimum ét spor"
+OutputWarnings.MultiTrackRecording="Advarsel: Visse formater (såsom FLV) understøtter ikke flere spor pr. optagelse"
+OutputWarnings.MP4Recording="Advarsel: MP4-optagelser vil ikke kunne genoprettes, hvis filen ikke kan færdiggøres (f.eks. som følge af BSODs, strømafbrydelse m.v.). Ønsker du at optage flere lydspor, overvej da at benytte MKV, og remuxe optagelsen til MP4, efter at den er færdiggjort (fil-> Remux optagelser)"
diff --git a/UI/data/locale/de-DE.ini b/UI/data/locale/de-DE.ini
index b42c6c8..1c43078 100644
--- a/UI/data/locale/de-DE.ini
+++ b/UI/data/locale/de-DE.ini
@@ -3,7 +3,7 @@ Language="Deutsch"
Region="Deutschland"
OK="OK"
-Apply="Anwenden"
+Apply="Übernehmen"
Cancel="Abbrechen"
Close="Schließen"
Save="Speichern"
@@ -41,7 +41,7 @@ Duplicate="Klonen"
Enable="Aktivieren"
DisableOSXVSync="OSX V-Sync deaktivieren"
ResetOSXVSyncOnExit="OSX V-Sync beim Beenden zurücksetzen"
-HighResourceUsage="Kodierung überlastet! Erwägen Sie Ihre Video-Einstellungen zu verringern, oder benutzen Sie eine schnellere Encoder-Voreinstellung."
+HighResourceUsage="Codierung überlastet! Erwägen Sie Ihre Video-Einstellungen zu verringern, oder benutzen Sie eine schnellere Codierer-Voreinstellung."
Transition="Übergang"
QuickTransitions="Schnelle Übergänge"
Left="Links"
@@ -49,6 +49,26 @@ Right="Rechts"
Top="Oben"
Bottom="Unten"
Reset="Zurücksetzen"
+Hours="Stunde(n)"
+Minutes="Minute(n)"
+Seconds="Sekunde(n)"
+Deprecated="Veraltet"
+ReplayBuffer="Replaypuffer"
+Import="Importieren"
+Export="Exportieren"
+
+Updater.Title="Neues Update verfügbar"
+Updater.Text="Es ist ein neues Update verfügbar:"
+Updater.UpdateNow="Jetzt updaten"
+Updater.RemindMeLater="Später erinnern"
+Updater.Skip="Version überspringen"
+Updater.Running.Title="Programm derzeit aktiv"
+Updater.Running.Text="Ausgänge sind derzeit aktiv. Bitte beenden Sie alle aktiven Ausgänge, bevor Sie versuchen OBS zu aktualisieren."
+Updater.NoUpdatesAvailable.Title="Keine Updates verfügbar"
+Updater.NoUpdatesAvailable.Text="Zurzeit sind keine Updates verfügbar"
+Updater.FailedToLaunch="Konnte den Updater nicht starten"
+Updater.GameCaptureActive.Title="Spielaufnahme aktiv"
+Updater.GameCaptureActive.Text="Spielaufnahme Hook Bibliothek wird zurzeit verwendet. Bitte schließen Sie alle derzeitigen Spiele / Programme die aufgenommen werden (oder starten Sie Windows neu) und versuchen Sie es erneut."
QuickTransitions.SwapScenes="Tausche Vorschau/Ausgabe-Szenen nach dem Übergang"
QuickTransitions.SwapScenesTT="Vertauscht die Vorschau- und Ausgabe-Szenen nach dem Übergang (falls die ursprüngliche Ausgabe-Szene noch vorhanden ist).\nEventuelle Änderungen an der original Ausgabe-Szene werden hierbei nicht rückgängig gemacht."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Entfernen bestätigen"
ConfirmRemove.Text="Sind Sie sicher, dass Sie '$1' entfernen möchten?"
ConfirmRemove.TextMultiple="Sind Sie sicher, dass Sie %1 Elemente löschen möchten?"
+Output.StartStreamFailed="Fehler beim Start des Streams"
+Output.StartRecordingFailed="Fehler beim Starten der Aufnahme"
+Output.StartReplayFailed="Fehler beim Starten des Replaypuffers"
+Output.StartFailedGeneric="Start der Ausgabe fehlgeschlagen. Bitte überprüfen Sie die Logdatei für Details.\n\nHinweis: Wenn Sie die NVENC- oder AMD-Encoder verwenden, stellen Sie sicher, dass Ihre Videotreiber aktuell sind."
+
Output.ConnectFail.Title="Verbindung fehlgeschlagen"
Output.ConnectFail.BadPath="Ungültiger Pfad oder Verbindungs-URL. Bitte überprüfen Sie Ihre Einstellungen und stellen Sie sicher, dass diese korrekt sind."
Output.ConnectFail.ConnectFailed="Verbindung zum Server fehlgeschlagen"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Nicht genügend Speicherplatz"
Output.RecordNoSpace.Msg="Es gibt nicht genügend Speicherplatz, um die Aufnahme fortzusetzen."
Output.RecordError.Title="Aufnahmefehler"
Output.RecordError.Msg="Während der Aufnahme ist ein unbekannter Fehler aufgetreten."
+Output.ReplayBuffer.NoHotkey.Title="Kein Hotkey festgelegt!"
+Output.ReplayBuffer.NoHotkey.Msg="Kein Speichern Hotkey festgelegt für Replaypuffer. Legen Sie bitte den \"Speichern\" Hotkey fest, der zum Speichern der Replayaufnahmen verwendet werden soll."
Output.BadPath.Title="Ungültiger Dateipfad"
Output.BadPath.Text="Der konfigurierte Ausgabepfad ist ungültig. Bitte überprüfen Sie Ihre Einstellungen und stellen Sie sicher, dass ein gültiger Pfad angegeben wurde."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Oberes Feld zuerst"
Deinterlacing.BottomFieldFirst="Unteres Feld zuerst"
+VolControl.SliderUnmuted="Lautstärke-Schieberegler für '%1': %2"
+VolControl.SliderMuted="Lautstärke-Schieberegler für '%1': %2 (derzeit stumm geschaltet)"
+VolControl.Mute="'%1' stumm schalten"
+VolControl.Properties="Eigenschaften von '%1'"
+
Basic.Main.AddSceneDlg.Title="Szene hinzufügen"
Basic.Main.AddSceneDlg.Text="Bitte geben Sie einen Namen für die Szene ein"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Szenen"
Basic.Main.Sources="Quellen"
Basic.Main.Connecting="Verbinden..."
Basic.Main.StartRecording="Aufnahme starten"
+Basic.Main.StartReplayBuffer="Replaypuffer starten"
Basic.Main.StartStreaming="Streaming starten"
Basic.Main.StopRecording="Aufnahme stoppen"
Basic.Main.StoppingRecording="Stoppe Aufnahme..."
+Basic.Main.StopReplayBuffer="Replaypuffer stoppen"
+Basic.Main.StoppingReplayBuffer="Stoppe Replaypuffer..."
Basic.Main.StopStreaming="Streaming stoppen"
Basic.Main.StoppingStreaming="Stoppe Stream..."
Basic.Main.ForceStopStreaming="Streaming stoppen (Verzögerung verwerfen)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="Wiede&rherstellen"
Basic.MainMenu.Edit.UndoAction="$1 rückgängig machen (&U)"
Basic.MainMenu.Edit.RedoAction="$1 Wiede&rherstellen"
Basic.MainMenu.Edit.LockPreview="Vorschau sperren (&L)"
+Basic.MainMenu.Edit.Scale="Vorschau&skalierung"
+Basic.MainMenu.Edit.Scale.Window="An Fenstergröße anpassen"
+Basic.MainMenu.Edit.Scale.Canvas="Leinwand (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Ausgabe (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformieren"
Basic.MainMenu.Edit.Transform.EditTransform="Transformation b&earbeiten..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Transformation kopieren"
+Basic.MainMenu.Edit.Transform.PasteTransform="Transformation einfügen"
Basic.MainMenu.Edit.Transform.ResetTransform="Transformation zu&rücksetzen"
Basic.MainMenu.Edit.Transform.Rotate90CW="Um 90° im Uhrzeigersinn drehen"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Um 90° gegen den Uhrzeigersinn drehen"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Statusleiste"
Basic.MainMenu.SceneCollection="&Szenen-Sammlung"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Profil importieren"
+Basic.MainMenu.Profile.Export="Profil exportieren"
+Basic.MainMenu.SceneCollection.Import="Szenen-Sammlung importieren"
+Basic.MainMenu.SceneCollection.Export="Szenen-Sammlung exportieren"
+Basic.MainMenu.Profile.Exists="Das Profil ist bereits vorhanden"
+Basic.MainMenu.SceneCollection.Exists="Die Szenen-Sammlung existiert bereits"
Basic.MainMenu.Tools="Werkzeuge (&T)"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Sie haben ungespeicherte Änderungen. Änderungen speich
Basic.Settings.General="Allgemein"
Basic.Settings.General.Theme="Motiv"
Basic.Settings.General.Language="Sprache"
+Basic.Settings.General.EnableAutoUpdates="Beim Start nach Updates suchen"
Basic.Settings.General.WarnBeforeStartingStream="Bestätigungsdialog beim Streamstart anzeigen"
Basic.Settings.General.WarnBeforeStoppingStream="Bestätigungsdialog beim Streamstop anzeigen"
+Basic.Settings.General.Projectors="Projektoren"
Basic.Settings.General.HideProjectorCursor="Mauszeiger über Projektoren verstecken"
Basic.Settings.General.ProjectorAlwaysOnTop="Projektoren immer im Vordergrund anzeigen"
Basic.Settings.General.Snapping="Quellenausrichtung"
@@ -336,17 +385,21 @@ Basic.Settings.General.ScreenSnapping="Quellen am Bildschirmrand ausrichten"
Basic.Settings.General.CenterSnapping="Quellen zur horizontalen und vertikalen Mitte ausrichten"
Basic.Settings.General.SourceSnapping="Quellen an anderen Quellen ausrichten"
Basic.Settings.General.SnapDistance="Ausrichtungsempfindlichkeit"
-Basic.Settings.General.RecordWhenStreaming="Stream automatisch aufnehmen"
+Basic.Settings.General.RecordWhenStreaming="Livestream automatisch aufnehmen"
Basic.Settings.General.KeepRecordingWhenStreamStops="Weiter aufnehmen, wenn der Livestream stoppt"
-Basic.Settings.General.SysTrayEnabled="Symbol in der Taskleiste aktivieren"
-Basic.Settings.General.SysTrayWhenStarted="Beim Start zur Taskleiste minimieren"
+Basic.Settings.General.ReplayBufferWhileStreaming="Replaypuffer automatisch starten, beim Streamen"
+Basic.Settings.General.KeepReplayBufferStreamStops="Replaypuffer weiter aktiv lassen, wenn der Livestream stoppt"
+Basic.Settings.General.SysTray="Infobereich"
+Basic.Settings.General.SysTrayWhenStarted="Beim Start zum Infobereich minimieren"
+Basic.Settings.General.SystemTrayHideMinimize="Immer zum Infobereich. statt zur Taskleiste minimieren"
+Basic.Settings.General.SaveProjectors="Projektoren beim Beenden speichern"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Stream Typ"
Basic.Settings.Output="Ausgabe"
Basic.Settings.Output.Format="Aufnahmeformat"
-Basic.Settings.Output.Encoder="Encoder"
+Basic.Settings.Output.Encoder="Codierer"
Basic.Settings.Output.SelectDirectory="Wählen Sie das Aufnahmeverzeichnis"
Basic.Settings.Output.SelectFile="Wählen Sie die Aufnahmedatei"
Basic.Settings.Output.EnforceBitrate="Erzwinge Bitratenlimit des Streamingdiensts"
@@ -354,19 +407,27 @@ Basic.Settings.Output.Mode="Ausgabemodus"
Basic.Settings.Output.Mode.Simple="Einfach"
Basic.Settings.Output.Mode.Adv="Erweitert"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg Ausgabe"
+Basic.Settings.Output.UseReplayBuffer="Replaypuffer aktivieren"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximale Replayzeit (Sekunden)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximale Speichernutzung (RAM) in Megabyte"
+Basic.Settings.Output.ReplayBuffer.Estimate="Geschätzte Speichernutzung (RAM): %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Speichernutzung kann nicht geschätzt werden. Stellen Sie bitte die maximale Speichergrenze ein."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Hinweis: Achten Sie darauf, einen Hotkey für den Replaypuffer im Abschnitt Hotkeys festzulegen)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Replaypuffer Dateiname Prefix"
+Basic.Settings.Output.ReplayBuffer.Suffix="Suffix"
Basic.Settings.Output.Simple.SavePath="Aufnahmepfad"
Basic.Settings.Output.Simple.RecordingQuality="Aufnahmequalität"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Gleiche wie Stream"
Basic.Settings.Output.Simple.RecordingQuality.Small="Hohe Qualität, mittelgroße Dateien"
Basic.Settings.Output.Simple.RecordingQuality.HQ="Ununterscheidbare Qualität, große Dateien"
Basic.Settings.Output.Simple.RecordingQuality.Lossless="Verlustfreie Qualität, enorm große Dateien"
-Basic.Settings.Output.Simple.Warn.VideoBitrate="Warnung: Die Videobitrate beim streamen wird auf %1 festlegt, was der Obergrenze des aktuellen Streamingdiensts entspricht. Falls Sie sicher sind, dass Sie %1 überschreiten wollen, deaktivieren Sie \"Erzwinge Bitratenlimit des Streamingdiensts\" in den erweiterten Encodereinstellungen."
-Basic.Settings.Output.Simple.Warn.AudioBitrate="Warnung: Die Audiobitrate beim streamen wird auf %1 festlegt, was der Obergrenze des aktuellen Streamingdiensts entspricht. Falls Sie sicher sind, dass Sie %1 überschreiten wollen, deaktivieren Sie \"Erzwinge Bitratenlimit des Streamingdiensts\" in den erweiterten Encodereinstellungen."
-Basic.Settings.Output.Simple.Warn.Encoder="Warnung: Mit einem Software-Encoder in einer anderen Qualität als der des Stream aufzunehmen wird zusätzliche CPU-Auslastung erzeugen, wenn Sie gleichzeitig streamen und aufzeichnen."
+Basic.Settings.Output.Simple.Warn.VideoBitrate="Warnung: Die Videobitrate beim streamen wird auf %1 festlegt, was der Obergrenze des aktuellen Streamingdiensts entspricht. Falls Sie sicher sind, dass Sie %1 überschreiten wollen, deaktivieren Sie \"Erzwinge Bitratenlimit des Streamingdiensts\" in den erweiterten Codierereinstellungen."
+Basic.Settings.Output.Simple.Warn.AudioBitrate="Warnung: Die Audiobitrate beim streamen wird auf %1 festlegt, was der Obergrenze des aktuellen Streamingdiensts entspricht. Falls Sie sicher sind, dass Sie %1 überschreiten wollen, deaktivieren Sie \"Erzwinge Bitratenlimit des Streamingdiensts\" in den erweiterten Codierereinstellungen."
+Basic.Settings.Output.Simple.Warn.Encoder="Warnung: Mit einem Software-Codierer in einer anderen Qualität als der des Stream aufzunehmen wird zusätzliche CPU-Auslastung erzeugen, wenn Sie gleichzeitig streamen und aufzeichnen."
Basic.Settings.Output.Simple.Warn.Lossless="Warnung: Verlustfreie Qualität erzeugt enorm große Dateien! Verlustfreie Qualität, kann mehr als 7 Gigabyte Speicherplatz pro Minute, bei hohen Auflösungen und Frameraten in Anspruch nehmen. Verlustfrei ist für lange Aufnahmen nicht empfohlen, es sei denn, Sie haben eine sehr große Menge an Speicherplatz zur Verfügung."
Basic.Settings.Output.Simple.Warn.Lossless.Msg="Sind Sie sicher, dass Sie verlustfreie Qualität verwenden möchten?"
Basic.Settings.Output.Simple.Warn.Lossless.Title="Verlustfreie Qualität-Warnung!"
-Basic.Settings.Output.Simple.Warn.MultipleQSV="Achtung: Sie können nicht mehrere separate QSV-Encoder beim streamen und aufnehmen gleichzeitig verwenden. Wenn Sie zur gleichen Zeit streamen und aufnehmen möchten, dann ändern Sie bitte entweder den Aufnahme-Encoder oder den Stream-Encoder."
+Basic.Settings.Output.Simple.Warn.MultipleQSV="Achtung: Sie können nicht mehrere separate QSV-Codierer beim streamen und aufnehmen gleichzeitig verwenden. Wenn Sie zur gleichen Zeit streamen und aufnehmen möchten, dann ändern Sie bitte entweder den Aufnahmecodierer oder den Streamcodierer."
Basic.Settings.Output.Simple.Encoder.Software="Software (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)"
Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)"
@@ -377,26 +438,28 @@ Basic.Settings.Output.AudioBitrate="Audiobitrate"
Basic.Settings.Output.Reconnect="Automatisch wiederverbinden"
Basic.Settings.Output.RetryDelay="Wiederverbindungsverzögerung (Sekunden)"
Basic.Settings.Output.MaxRetries="Maximale Wiederholungsversuche"
-Basic.Settings.Output.Advanced="Erweiterte Encodereinstellungen aktivieren"
-Basic.Settings.Output.EncoderPreset="Encoder-Voreinstellung (höher = weniger CPU Auslastung)"
-Basic.Settings.Output.CustomEncoderSettings="Benutzerdefinierte Encoder-Einstellungen"
+Basic.Settings.Output.Advanced="Erweiterte Codierereinstellungen aktivieren"
+Basic.Settings.Output.EncoderPreset="Codierer-Voreinstellung (höher = weniger CPU Auslastung)"
+Basic.Settings.Output.CustomEncoderSettings="Benutzerdefinierte Codierer-Einstellungen"
Basic.Settings.Output.CustomMuxerSettings="Benutzerdefinierte Muxereinstellungen"
Basic.Settings.Output.NoSpaceFileName="Dateinamen ohne Leerzeichen generieren"
Basic.Settings.Output.Adv.Rescale="Ausgabe umskalieren"
Basic.Settings.Output.Adv.AudioTrack="Audiospur"
Basic.Settings.Output.Adv.Streaming="Streamen"
-Basic.Settings.Output.Adv.ApplyServiceSettings="Erzwinge Streamingdienst-Encodereinstellungen"
+Basic.Settings.Output.Adv.ApplyServiceSettings="Erzwinge Streamingdienst-Codierereinstellungen"
Basic.Settings.Output.Adv.Audio.Track1="Spur 1"
Basic.Settings.Output.Adv.Audio.Track2="Spur 2"
Basic.Settings.Output.Adv.Audio.Track3="Spur 3"
Basic.Settings.Output.Adv.Audio.Track4="Spur 4"
+Basic.Settings.Output.Adv.Audio.Track5="Spur 5"
+Basic.Settings.Output.Adv.Audio.Track6="Spur 6"
Basic.Settings.Output.Adv.Recording="Aufnehmen"
Basic.Settings.Output.Adv.Recording.Type="Art"
Basic.Settings.Output.Adv.Recording.Type.Standard="Normal"
Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Benutzerdefinierte Ausgabe (FFmpeg)"
-Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Benutze Streamencoder)"
+Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Benutze Streamcodierer)"
Basic.Settings.Output.Adv.Recording.Filename="Dateinameformatierung"
Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Überschreiben, wenn die Datei vorhanden ist"
Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg-Ausgabetyp"
@@ -411,13 +474,15 @@ Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Video"
Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Standardformat"
Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Container-Formatbeschreibung"
Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Audio- / Videocodec wird aus Dateipfad oder URL erraten."
-Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Standard-Encoder"
-Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Encoder deaktivieren"
-Basic.Settings.Output.Adv.FFmpeg.VEncoder="Video-Encoder"
-Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Video Encoder-Einstellungen (falls gewünscht)"
-Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio-Encoder"
-Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audio Encoder-Einstellungen (falls gewünscht)"
+Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Standard-Codierer"
+Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Codierer deaktivieren"
+Basic.Settings.Output.Adv.FFmpeg.VEncoder="Video-Codierer"
+Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Video Codierer-Einstellungen (falls gewünscht)"
+Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio-Codierer"
+Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audio Codierer-Einstellungen (falls gewünscht)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer Einstellungen (falls vorhanden)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Keyframeintervall (Frames)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Zeige alle Codecs (auch wenn möglicherweise nicht kompatibel)"
FilenameFormatting.completer="%DD-%MM-%CCYY %hh-%mm-%ss\n%DD-%MM-%YY %hh-%mm-%ss\n%d-%m-%Y %H-%M-%S\n%d-%m-%y %H-%M-%S\n%a %d-%m-%Y %H-%M-%S\n%A %d-%m-%Y %H-%M-%S\n%d-%b-%Y %H-%M-%S\n%d-%B-%Y %H-%M-%S"
@@ -471,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV-Farbmatrix"
Basic.Settings.Advanced.Video.ColorRange="YUV Farbbereich"
Basic.Settings.Advanced.Video.ColorRange.Partial="Begrenzt"
Basic.Settings.Advanced.Video.ColorRange.Full="Voll"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Audiomonitoringgerät"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Standard"
Basic.Settings.Advanced.StreamDelay="Stream-Verzögerung"
Basic.Settings.Advanced.StreamDelay.Duration="Dauer (Sekunden)"
Basic.Settings.Advanced.StreamDelay.Preserve="Lückenloses Wiederverbinden (erhöht Verzögerung, um Videoverlust zu vermeiden)"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Geschätzte Speichernutzung: %1 MB"
Basic.Settings.Advanced.Network="Netzwerk"
Basic.Settings.Advanced.Network.BindToIP="Interface"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Neuen Netzwerkcode aktivieren"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Niedriger Latenzmodus"
Basic.AdvAudio="Erweiterte Audioeigenschaften"
Basic.AdvAudio.Name="Name"
@@ -484,21 +553,21 @@ Basic.AdvAudio.Volume="Lautstärke (%)"
Basic.AdvAudio.Mono="Heruntermischen zu Mono"
Basic.AdvAudio.Panning="Schwenken"
Basic.AdvAudio.SyncOffset="Sync Verschiebung (ms)"
+Basic.AdvAudio.Monitoring="Audiomonitoring"
+Basic.AdvAudio.Monitoring.None="Monitor aus"
+Basic.AdvAudio.Monitoring.MonitorOnly="Nur Monitor (Ausgabe stumm schalten)"
+Basic.AdvAudio.Monitoring.Both="Monitor und Ausgabe"
Basic.AdvAudio.AudioTracks="Spuren"
Basic.Settings.Hotkeys="Hotkeys"
Basic.Settings.Hotkeys.Pair="Mit '%1' geteilte Tastenkombinationen funktionieren als Schalter"
-Basic.Hotkeys.StartStreaming="Streaming starten"
-Basic.Hotkeys.StopStreaming="Streaming stoppen"
-Basic.Hotkeys.StartRecording="Aufnahme starten"
-Basic.Hotkeys.StopRecording="Aufnahme stoppen"
Basic.Hotkeys.SelectScene="Zu Szene wechseln"
Basic.SystemTray.Show="Anzeigen"
Basic.SystemTray.Hide="Ausblenden"
-Basic.SystemTray.Message.Reconnecting="Verbindung verloren. Verbinde erneut..."
+Basic.SystemTray.Message.Reconnecting="Verbindung verloren. Verbinde erneut..."
Hotkeys.Insert="Einfügen"
Hotkeys.Delete="Entfernen"
@@ -546,4 +615,5 @@ SceneItemHide="'%1' verstecken"
OutputWarnings.NoTracksSelected="Sie müssen mindestens eine Spur auswählen"
OutputWarnings.MultiTrackRecording="Warnung: Bestimmte Formate (z. B. FLV) unterstützen nicht mehrere Spuren pro Aufnahme"
+OutputWarnings.MP4Recording="Warnung: Aufnahmen, die in MP4 gespeichert werden, sind nicht wiederherstellbar, wenn die Datei nicht abgeschlossen werden kann (zum Beispiel als Folge von BSODs, Stromausfälle, etc). Wenn Sie mehrere Audiospuren aufnehmen möchten, sollten Sie MKV verwenden und die Aufnahme zu MP4 remuxen, nachdem sie fertig ist. (Datei-> Remuxe Aufnahmen)"
diff --git a/UI/data/locale/el-GR.ini b/UI/data/locale/el-GR.ini
index 4ecdca7..59839a4 100644
--- a/UI/data/locale/el-GR.ini
+++ b/UI/data/locale/el-GR.ini
@@ -8,6 +8,7 @@ Cancel="Ακύρωση"
Close="Κλείσιμο"
Save="Αποθήκευση"
Discard="Απόρριψη"
+Disable="Απενεργοποίηση"
Yes="Ναι"
No="Όχι"
Add="Προσθήκη"
@@ -39,6 +40,14 @@ New="Νέο"
Duplicate="Διπλότυπη εγγραφή"
Enable="Ενεργοποίηση"
DisableOSXVSync="Απενεργοποίηση OSX V-Sync"
+Left="Αριστερά"
+Right="Δεξιά"
+Top="Επάνω"
+Bottom="Κάτω"
+Hours="Ώρες"
+Minutes="Λεπτά"
+Seconds="Δευτερόλεπτα"
+
Basic.TransitionDuration="Διάρκεια"
@@ -61,6 +70,7 @@ ConfirmExit.Title="Έξοδος από το OBS;"
ConfirmRemove.Title="Επιβεβαίωση Αφαίρεσης"
ConfirmRemove.Text="Είστε βέβαιοι ότι θέλετε να καταργήσετε \"$1\";"
+
Output.ConnectFail.Title="Η σύνδεση απέτυχε"
Output.ConnectFail.BadPath="Μη έγκυρη Διαδρομή ή URL Σύνδεσης. Παρακαλώ ελέγξτε τις ρυθμίσεις σας και επιβεβαιώστε ότι είναι έγκυρες."
Output.ConnectFail.ConnectFailed="Απέτυχε η σύνδεση στον διακομιστή"
@@ -113,6 +123,7 @@ Basic.Main.PreviewConextMenu.Enable="Ενεργοποίηση Προεπισκό
+
Basic.Main.AddSceneDlg.Title="Προσθήκη Σκηνής"
Basic.Main.AddSceneDlg.Text="Παρακαλώ εισάγετε το όνομα της σκηνής"
@@ -353,10 +364,6 @@ Basic.AdvAudio.SyncOffset="Μετατόπιση Συγχρονισμού (ms)"
Basic.AdvAudio.AudioTracks="Κομμάτια"
-Basic.Hotkeys.StartStreaming="Έναρξη Μετάδοσης"
-Basic.Hotkeys.StopStreaming="Διακοπή Μετάδοσης"
-Basic.Hotkeys.StartRecording="Έναρξη Καταγραφής"
-Basic.Hotkeys.StopRecording="Διακοπή Καταγραφής"
Basic.Hotkeys.SelectScene="Μετάβαση σε σκηνή"
diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index 3d6f196..1d3b3f9 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -54,6 +54,27 @@ Right="Right"
Top="Top"
Bottom="Bottom"
Reset="Reset"
+Hours="Hours"
+Minutes="Minutes"
+Seconds="Seconds"
+Deprecated="Deprecated"
+ReplayBuffer="Replay Buffer"
+Import="Import"
+Export="Export"
+
+# updater
+Updater.Title="New update available"
+Updater.Text="There is a new update available:"
+Updater.UpdateNow="Update Now"
+Updater.RemindMeLater="Remind me Later"
+Updater.Skip="Skip Version"
+Updater.Running.Title="Program currently active"
+Updater.Running.Text="Outputs are currently active, please shut down any active outputs before attempting to update"
+Updater.NoUpdatesAvailable.Title="No updates available"
+Updater.NoUpdatesAvailable.Text="No updates are currently available"
+Updater.FailedToLaunch="Failed to launch updater"
+Updater.GameCaptureActive.Title="Game capture active"
+Updater.GameCaptureActive.Text="Game capture hook library is currently in use. Please close any games/programs being captured (or restart windows) and try again."
# quick transitions
QuickTransitions.SwapScenes="Swap Preview/Output Scenes After Transitioning"
@@ -104,6 +125,12 @@ ConfirmRemove.Title="Confirm Remove"
ConfirmRemove.Text="Are you sure you wish to remove '$1'?"
ConfirmRemove.TextMultiple="Are you sure you wish to remove %1 items?"
+# output start messages
+Output.StartStreamFailed="Failed to start streaming"
+Output.StartRecordingFailed="Failed to start recording"
+Output.StartReplayFailed="Failed to start replay buffer"
+Output.StartFailedGeneric="Starting the output failed. Please check the log for details.\n\nNote: If you are using the NVENC or AMD encoders, make sure your video drivers are up to date."
+
# output connect messages
Output.ConnectFail.Title="Failed to connect"
Output.ConnectFail.BadPath="Invalid Path or Connection URL. Please check your settings to confirm that they are valid."
@@ -119,6 +146,8 @@ Output.RecordNoSpace.Title="Insufficient disk space"
Output.RecordNoSpace.Msg="There is not sufficient disk space to continue recording."
Output.RecordError.Title="Recording error"
Output.RecordError.Msg="An unspecified error occurred while recording."
+Output.ReplayBuffer.NoHotkey.Title="No hotkey set!"
+Output.ReplayBuffer.NoHotkey.Msg="No save hotkey set for replay buffer. Please set the \"Save\" hotkey to use for saving replay recordings."
# output recording messages
Output.BadPath.Title="Bad File Path"
@@ -190,6 +219,12 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Top Field First"
Deinterlacing.BottomFieldFirst="Bottom Field First"
+# volume control accessibility text
+VolControl.SliderUnmuted="Volume slider for '%1': %2"
+VolControl.SliderMuted="Volume slider for '%1': %2 (currently muted)"
+VolControl.Mute="Mute '%1'"
+VolControl.Properties="Properties for '%1'"
+
# add scene dialog
Basic.Main.AddSceneDlg.Title="Add Scene"
Basic.Main.AddSceneDlg.Text="Please enter the name of the scene"
@@ -300,9 +335,12 @@ Basic.Main.Scenes="Scenes"
Basic.Main.Sources="Sources"
Basic.Main.Connecting="Connecting..."
Basic.Main.StartRecording="Start Recording"
+Basic.Main.StartReplayBuffer="Start Replay Buffer"
Basic.Main.StartStreaming="Start Streaming"
Basic.Main.StopRecording="Stop Recording"
Basic.Main.StoppingRecording="Stopping Recording..."
+Basic.Main.StopReplayBuffer="Stop Replay Buffer"
+Basic.Main.StoppingReplayBuffer="Stopping Replay Buffer..."
Basic.Main.StopStreaming="Stop Streaming"
Basic.Main.StoppingStreaming="Stopping Stream..."
Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)"
@@ -326,8 +364,14 @@ Basic.MainMenu.Edit.Redo="&Redo"
Basic.MainMenu.Edit.UndoAction="&Undo $1"
Basic.MainMenu.Edit.RedoAction="&Redo $1"
Basic.MainMenu.Edit.LockPreview="&Lock Preview"
+Basic.MainMenu.Edit.Scale="Preview &Scaling"
+Basic.MainMenu.Edit.Scale.Window="Scale to Window"
+Basic.MainMenu.Edit.Scale.Canvas="Canvas (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Output (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transform"
Basic.MainMenu.Edit.Transform.EditTransform="&Edit Transform..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Copy Transform"
+Basic.MainMenu.Edit.Transform.PasteTransform="Paste Transform"
Basic.MainMenu.Edit.Transform.ResetTransform="&Reset Transform"
Basic.MainMenu.Edit.Transform.Rotate90CW="Rotate 90 degrees CW"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotate 90 degrees CCW"
@@ -354,6 +398,12 @@ Basic.MainMenu.View.StatusBar="&Status Bar"
# basic mode profile/scene collection menus
Basic.MainMenu.SceneCollection="&Scene Collection"
Basic.MainMenu.Profile="&Profile"
+Basic.MainMenu.Profile.Import="Import Profile"
+Basic.MainMenu.Profile.Export="Export Profile"
+Basic.MainMenu.SceneCollection.Import="Import Scene Collection"
+Basic.MainMenu.SceneCollection.Export="Export Scene Collection"
+Basic.MainMenu.Profile.Exists="The profile already exists"
+Basic.MainMenu.SceneCollection.Exists="The scene collection already exists"
# basic mode help menu
Basic.MainMenu.Tools="&Tools"
@@ -377,8 +427,10 @@ Basic.Settings.Confirm="You have unsaved changes. Save changes?"
Basic.Settings.General="General"
Basic.Settings.General.Theme="Theme"
Basic.Settings.General.Language="Language"
+Basic.Settings.General.EnableAutoUpdates="Automatically check for updates on startup"
Basic.Settings.General.WarnBeforeStartingStream="Show confirmation dialog when starting streams"
Basic.Settings.General.WarnBeforeStoppingStream="Show confirmation dialog when stopping streams"
+Basic.Settings.General.Projectors="Projectors"
Basic.Settings.General.HideProjectorCursor="Hide cursor over projectors"
Basic.Settings.General.ProjectorAlwaysOnTop="Make projectors always on top"
Basic.Settings.General.Snapping="Source Alignment Snapping"
@@ -388,8 +440,12 @@ Basic.Settings.General.SourceSnapping="Snap Sources to other sources"
Basic.Settings.General.SnapDistance="Snap Sensitivity"
Basic.Settings.General.RecordWhenStreaming="Automatically record when streaming"
Basic.Settings.General.KeepRecordingWhenStreamStops="Keep recording when stream stops"
-Basic.Settings.General.SysTrayEnabled="Enable system tray icon"
+Basic.Settings.General.ReplayBufferWhileStreaming="Automatically start replay buffer when streaming"
+Basic.Settings.General.KeepReplayBufferStreamStops="Keep replay buffer active when stream stops"
+Basic.Settings.General.SysTray="System Tray"
Basic.Settings.General.SysTrayWhenStarted="Minimize to system tray when started"
+Basic.Settings.General.SystemTrayHideMinimize="Always minimize to system tray instead of task bar"
+Basic.Settings.General.SaveProjectors="Save projectors on exit"
# basic mode 'stream' settings
Basic.Settings.Stream="Stream"
@@ -406,6 +462,14 @@ Basic.Settings.Output.Mode="Output Mode"
Basic.Settings.Output.Mode.Simple="Simple"
Basic.Settings.Output.Mode.Adv="Advanced"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg Output"
+Basic.Settings.Output.UseReplayBuffer="Enable Replay Buffer"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximum Replay Time (Seconds)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximum Memory (Megabytes)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Estimated memory usage: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Cannot estimate memory usage. Please set maximum memory limit."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Note: Make sure to set a hotkey for the replay buffer in the hotkeys section)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Replay Buffer Filename Prefix"
+Basic.Settings.Output.ReplayBuffer.Suffix="Suffix"
Basic.Settings.Output.Simple.SavePath="Recording Path"
Basic.Settings.Output.Simple.RecordingQuality="Recording Quality"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Same as stream"
@@ -444,6 +508,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Track 1"
Basic.Settings.Output.Adv.Audio.Track2="Track 2"
Basic.Settings.Output.Adv.Audio.Track3="Track 3"
Basic.Settings.Output.Adv.Audio.Track4="Track 4"
+Basic.Settings.Output.Adv.Audio.Track5="Track 5"
+Basic.Settings.Output.Adv.Audio.Track6="Track 6"
# basic mode 'output' settings - advanced section - recording subsection
Basic.Settings.Output.Adv.Recording="Recording"
@@ -472,12 +538,14 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Video Encoder Settings (if an
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio Encoder"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audio Encoder Settings (if any)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer Settings (if any)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Keyframe interval (frames)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Show all codecs (even if potentially incompatible)"
# basic mode 'output' settings - advanced section - recording subsection - completer
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
# basic mode 'output' settings - advanced section - recording subsection - TT
-FilenameFormatting.TT="%CCYY Year, four digits\n%YY Year, last two digits (00-99)\n%MM Month as a decimal number (01-12)\n%DD Day of the month, zero-padded (01-31)\n%hh Hour in 24h format (00-23)\n%mm Minute (00-59)\n%ss Second (00-61)\n%% A % sign\n%a Abbreviated weekday name\n%A Full weekday name\n%b Abbreviated month name\n%B Full month name\n%d Day of the month, zero-padded (01-31)\n%H Hour in 24h format (00-23)\n%I Hour in 12h format (01-12)\n%m Month as a decimal number (01-12)\n%M Minute (00-59)\n%p AM or PM designation\n%S Second (00-61)\n%y Year, last two digits (00-99)\n%Y Year\n%z ISO 8601 offset from UTC or timezone\n name or abbreviation\n%Z Timezone name or abbreviation\n"
+FilenameFormatting.TT="%CCYY Year, four digits\n%YY Year, last two digits (00-99)\n%MM Month as a decimal number (01-12)\n%DD Day of the month, zero-padded (01-31)\n%hh Hour in 24h format (00-23)\n%mm Minute (00-59)\n%ss Second (00-61)\n%% A % sign\n%a Abbreviated weekday name\n%A Full weekday name\n%b Abbreviated month name\n%B Full month name\n%d Day of the month, zero-padded (01-31)\n%H Hour in 24h format (00-23)\n%I Hour in 12h format (01-12)\n%m Month as a decimal number (01-12)\n%M Minute (00-59)\n%p AM or PM designation\n%S Second (00-61)\n%y Year, last two digits (00-99)\n%Y Year\n%z ISO 8601 offset from UTC or timezone\n name or abbreviation\n%Z Timezone name or abbreviation\n"
# basic mode 'video' settings
Basic.Settings.Video="Video"
@@ -531,12 +599,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV Color Space"
Basic.Settings.Advanced.Video.ColorRange="YUV Color Range"
Basic.Settings.Advanced.Video.ColorRange.Partial="Partial"
Basic.Settings.Advanced.Video.ColorRange.Full="Full"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Audio Monitoring Device"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Default"
Basic.Settings.Advanced.StreamDelay="Stream Delay"
Basic.Settings.Advanced.StreamDelay.Duration="Duration (seconds)"
Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase delay) when reconnecting"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimated Memory Usage: %1 MB"
Basic.Settings.Advanced.Network="Network"
Basic.Settings.Advanced.Network.BindToIP="Bind to IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Enable new networking code"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Low latency mode"
# advanced audio properties
Basic.AdvAudio="Advanced Audio Properties"
@@ -545,6 +617,10 @@ Basic.AdvAudio.Volume="Volume (%)"
Basic.AdvAudio.Mono="Downmix to Mono"
Basic.AdvAudio.Panning="Panning"
Basic.AdvAudio.SyncOffset="Sync Offset (ms)"
+Basic.AdvAudio.Monitoring="Audio Monitoring"
+Basic.AdvAudio.Monitoring.None="Monitor Off"
+Basic.AdvAudio.Monitoring.MonitorOnly="Monitor Only (mute output)"
+Basic.AdvAudio.Monitoring.Both="Monitor and Output"
Basic.AdvAudio.AudioTracks="Tracks"
# basic mode 'hotkeys' settings
@@ -552,10 +628,6 @@ Basic.Settings.Hotkeys="Hotkeys"
Basic.Settings.Hotkeys.Pair="Key combinations shared with '%1' act as toggles"
# basic mode hotkeys
-Basic.Hotkeys.StartStreaming="Start Streaming"
-Basic.Hotkeys.StopStreaming="Stop Streaming"
-Basic.Hotkeys.StartRecording="Start Recording"
-Basic.Hotkeys.StopRecording="Stop Recording"
Basic.Hotkeys.SelectScene="Switch to scene"
# system tray
@@ -615,3 +687,4 @@ SceneItemHide="Hide '%1'"
# Output warnings
OutputWarnings.NoTracksSelected="You must select at least one track"
OutputWarnings.MultiTrackRecording="Warning: Certain formats (such as FLV) do not support multiple tracks per recording"
+OutputWarnings.MP4Recording="Warning: Recordings saved to MP4 will be unrecoverable if the file cannot be finalized (e.g. as a result of BSODs, power losses, etc.). If you want to record multiple audio tracks consider using MKV and remux the recording to mp4 after it is finished (File->Remux Recordings)"
diff --git a/UI/data/locale/es-ES.ini b/UI/data/locale/es-ES.ini
index e988ac9..76aed31 100644
--- a/UI/data/locale/es-ES.ini
+++ b/UI/data/locale/es-ES.ini
@@ -49,6 +49,26 @@ Right="Derecha"
Top="Arriba"
Bottom="Abajo"
Reset="Reiniciar"
+Hours="Horas"
+Minutes="Minutos"
+Seconds="Segundos"
+Deprecated="Obsoleto"
+ReplayBuffer="Búfer de reproducción"
+Import="Importar"
+Export="Exportar"
+
+Updater.Title="Nueva actualización disponible"
+Updater.Text="Hay una nueva versión disponible:"
+Updater.UpdateNow="Actualizar ahora"
+Updater.RemindMeLater="Recordármelo más tarde"
+Updater.Skip="Saltar Versión"
+Updater.Running.Title="Programa actualmente activo"
+Updater.Running.Text="Las salidas están activas actualmente, por favor apague cualquier salida activa antes de intentar actualizar"
+Updater.NoUpdatesAvailable.Title="No hay actualizaciones disponibles"
+Updater.NoUpdatesAvailable.Text="No hay actualizaciones disponibles actualmente"
+Updater.FailedToLaunch="No se pudo iniciar el actualizador"
+Updater.GameCaptureActive.Title="Captura de juego activa"
+Updater.GameCaptureActive.Text="La libreria de captura de juegos esta actualmente en uso. Por favor, cierra cualquier juego/programa que este siendo capturado (o reinicia windows) e intentalo de nuevo."
QuickTransitions.SwapScenes="Cambiar vista previa y salida escenas después de la transición"
QuickTransitions.SwapScenesTT="Cambia la vista previa y salida escenas después de la transición (si todavía existe la escena original de la salida). \nEsto no deshará cualquier cambio que pueda haber hecho a la escena original de la salida."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Confirmar borrado"
ConfirmRemove.Text="¿Seguro que desea eliminar '$1'?"
ConfirmRemove.TextMultiple="¿Seguro que quieres eliminar %1 elementos?"
+Output.StartStreamFailed="No se pudo iniciar la emisión"
+Output.StartRecordingFailed="No se pudo iniciar grabación"
+Output.StartReplayFailed="No se pudo iniciar el buffer de replay"
+Output.StartFailedGeneric="No se pudo iniciar la salida. Por favor compruebe los logs para mas detalles. \n\nNota: Si estas usando los codificadores de NVENC o AMD, asegúrate que tus drivers de vídeo están actualizados."
+
Output.ConnectFail.Title="Error al conectarse"
Output.ConnectFail.BadPath="URL ruta de acceso o conexión no válida. Por favor, compruebe su configuración para confirmar que está correcta."
Output.ConnectFail.ConnectFailed="No se pudo conectar al servidor"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="No hay suficiente espacio en disco"
Output.RecordNoSpace.Msg="No hay suficiente espacio en disco para continuar grabando."
Output.RecordError.Title="Error en la grabación"
Output.RecordError.Msg="Se ha producido un error no especificado durante la grabación."
+Output.ReplayBuffer.NoHotkey.Title="¡Sin tecla de acceso rápido!"
+Output.ReplayBuffer.NoHotkey.Msg="Sin tecla de acceso rápido establecida para el búfer de reproducción. Configure la tecla de acceso \"Guardar\" para guardar las grabaciones de reproducción."
Output.BadPath.Title="Ruta de archivo incorrecta"
Output.BadPath.Text="La ruta de salida de archivos establecida no es válida. Por favor, compruebe su configuración para confirmar que se ha establecido una ruta de archivos válida."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Campo Superior Primero"
Deinterlacing.BottomFieldFirst="Campo Inferior Primero"
+VolControl.SliderUnmuted="Deslizador de volumen para '%1': %2"
+VolControl.SliderMuted="Deslizador de volumen para '%1': %2 (silenciado)"
+VolControl.Mute="Silenciar '%1'"
+VolControl.Properties="Propiedades para '%1'"
+
Basic.Main.AddSceneDlg.Title="Añadir escena"
Basic.Main.AddSceneDlg.Text="Por favor, introduzca el nombre de la escena"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Escenas"
Basic.Main.Sources="Fuentes"
Basic.Main.Connecting="Conectando..."
Basic.Main.StartRecording="Iniciar grabación"
+Basic.Main.StartReplayBuffer="Iniciar la reproducción del búfer"
Basic.Main.StartStreaming="Iniciar Transmisión"
Basic.Main.StopRecording="Detener grabación"
Basic.Main.StoppingRecording="Deteniendo la grabación..."
+Basic.Main.StopReplayBuffer="Detener la reproducción del búfer"
+Basic.Main.StoppingReplayBuffer="Deteniendo la reproducción del búfer..."
Basic.Main.StopStreaming="Detener Transmisión"
Basic.Main.StoppingStreaming="Deteniendo la trasmisión..."
Basic.Main.ForceStopStreaming="Parar Transmisión (descartar retraso)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="Reh&acer"
Basic.MainMenu.Edit.UndoAction="&Deshacer $1"
Basic.MainMenu.Edit.RedoAction="&Rehacer $1"
Basic.MainMenu.Edit.LockPreview="&Bloquear vista previa"
+Basic.MainMenu.Edit.Scale="Vista previa y escala"
+Basic.MainMenu.Edit.Scale.Window="Ajustar a la ventana"
+Basic.MainMenu.Edit.Scale.Canvas="Lienzo (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Salida (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformar"
Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformación..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Copiar transformación"
+Basic.MainMenu.Edit.Transform.PasteTransform="Pegar trasformación"
Basic.MainMenu.Edit.Transform.ResetTransform="&Restablecer transformación"
Basic.MainMenu.Edit.Transform.Rotate90CW="Girar 90 grados en el sentido de las agujas del reloj"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Girar 90 grados contra el sentido de las agujas del reloj"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Barra de Estado"
Basic.MainMenu.SceneCollection="&Colección de Escenas"
Basic.MainMenu.Profile="&Perfil"
+Basic.MainMenu.Profile.Import="Importar perfil"
+Basic.MainMenu.Profile.Export="Exportar perfil"
+Basic.MainMenu.SceneCollection.Import="Importar colección de escenas"
+Basic.MainMenu.SceneCollection.Export="Exportar colección de escenas"
+Basic.MainMenu.Profile.Exists="El perfil ya existe"
+Basic.MainMenu.SceneCollection.Exists="La colección de escenas ya existe"
Basic.MainMenu.Tools="&Herramientas"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Hay cambios sin guardar. ¿Guardar los cambios?"
Basic.Settings.General="General"
Basic.Settings.General.Theme="Tema"
Basic.Settings.General.Language="Idioma"
+Basic.Settings.General.EnableAutoUpdates="Comprobar actualizaciones automáticamente al inicio"
Basic.Settings.General.WarnBeforeStartingStream="Mostrar diálogo de confirmación cuando se inicia una transmisión"
Basic.Settings.General.WarnBeforeStoppingStream="Mostrar diálogo de confirmación cuando se para una transmisión"
+Basic.Settings.General.Projectors="Proyectores"
Basic.Settings.General.HideProjectorCursor="Ocultar el cursor sobre proyectores"
Basic.Settings.General.ProjectorAlwaysOnTop="Proyectores siempre en la parte superior"
Basic.Settings.General.Snapping="Ajuste de alineación de la fuente"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Ajustar las fuentes a otras fuentes"
Basic.Settings.General.SnapDistance="Ajustar la sensibilidad"
Basic.Settings.General.RecordWhenStreaming="Grabar automáticamente cuando se transmite"
Basic.Settings.General.KeepRecordingWhenStreamStops="Mantener la grabación cuando se detiene la trasmision"
-Basic.Settings.General.SysTrayEnabled="Activar icono en la bandeja del sistema"
+Basic.Settings.General.ReplayBufferWhileStreaming="Iniciar la reproducción del búfer automáticamente durante la transmisión"
+Basic.Settings.General.KeepReplayBufferStreamStops="Mantener activo el búfer de reproducción cuando la transmisión se detenga"
+Basic.Settings.General.SysTray="Bandeja del sistema"
Basic.Settings.General.SysTrayWhenStarted="Minimizar a la bandeja del sistema al iniciar"
+Basic.Settings.General.SystemTrayHideMinimize="Minimizar siempre en la bandeja del sistema en lugar de la barra de tareas"
+Basic.Settings.General.SaveProjectors="Guardar los proyectores al salir"
Basic.Settings.Stream="Emision"
Basic.Settings.Stream.StreamType="Tipo de Emision"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Modo de salida"
Basic.Settings.Output.Mode.Simple="Sencillo"
Basic.Settings.Output.Mode.Adv="Avanzado"
Basic.Settings.Output.Mode.FFmpeg="Salida de FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Activar la reproducción del búfer"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Tiempo de reproducción máximo (segundos)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Memoria máxima (MB)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Uso estimado de memoria: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="No se puede estimar el uso de memoria. Establezca el límite máximo de memoria."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Nota: Asegúrese de establecer una tecla de acceso rápido para el búfer de reproducción en la sección de teclas rápidas)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Prefijo del nombre de archivo del búfer"
+Basic.Settings.Output.ReplayBuffer.Suffix="Sufijo"
Basic.Settings.Output.Simple.SavePath="Ruta de grabación"
Basic.Settings.Output.Simple.RecordingQuality="Calidad de grabación"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Igual a la emision"
@@ -391,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Pista 1"
Basic.Settings.Output.Adv.Audio.Track2="Pista 2"
Basic.Settings.Output.Adv.Audio.Track3="Pista 3"
Basic.Settings.Output.Adv.Audio.Track4="Pista 4"
+Basic.Settings.Output.Adv.Audio.Track5="Pista 5"
+Basic.Settings.Output.Adv.Audio.Track6="Pista 6"
Basic.Settings.Output.Adv.Recording="Grabando"
Basic.Settings.Output.Adv.Recording.Type="Tipo"
@@ -418,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Configuración de codificador
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Codificador de audio"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Configuración de codificador de vídeo (si existe)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Ajustes de Muxer (en caso de que haya)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Intervalo de fotogramas clave (en Fotogramas)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Mostrar todos los codecs (aunque sean potencialmente incompatibles)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -471,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="Espacio de color YUV"
Basic.Settings.Advanced.Video.ColorRange="Gama de Color YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Parcial"
Basic.Settings.Advanced.Video.ColorRange.Full="Completo"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Dispositivo de monitorización de audio"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Por defecto"
Basic.Settings.Advanced.StreamDelay="Retraso de la transmisión"
Basic.Settings.Advanced.StreamDelay.Duration="Duración (segundos)"
Basic.Settings.Advanced.StreamDelay.Preserve="Preservar el punto de corte (aumento de retraso) al volver a conectar"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Uso estimado de memoria: %1 MB"
Basic.Settings.Advanced.Network="Red"
Basic.Settings.Advanced.Network.BindToIP="Enlazar con IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Habilitar el nuevo código de red"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Modo de baja latencia"
Basic.AdvAudio="Propiedades de Audio avanzadas"
Basic.AdvAudio.Name="Nombre"
@@ -484,15 +553,15 @@ Basic.AdvAudio.Volume="Volumen (%)"
Basic.AdvAudio.Mono="Remezclar a Mono"
Basic.AdvAudio.Panning="Panorámica"
Basic.AdvAudio.SyncOffset="Sincronización Offset (ms)"
+Basic.AdvAudio.Monitoring="Monitorización de audio"
+Basic.AdvAudio.Monitoring.None="Monitorización desactivada"
+Basic.AdvAudio.Monitoring.MonitorOnly="Solo monitorización (silenciar la salida)"
+Basic.AdvAudio.Monitoring.Both="Monitorización y salida"
Basic.AdvAudio.AudioTracks="Pistas"
Basic.Settings.Hotkeys="Atajos"
Basic.Settings.Hotkeys.Pair="Combinaciones de teclas con '%1' actúan como interruptores"
-Basic.Hotkeys.StartStreaming="Iniciar Transmisión"
-Basic.Hotkeys.StopStreaming="Detener Transmisión"
-Basic.Hotkeys.StartRecording="Iniciar grabación"
-Basic.Hotkeys.StopRecording="Detener grabación"
Basic.Hotkeys.SelectScene="Cambiar a la escena"
Basic.SystemTray.Show="Mostrar"
@@ -546,4 +615,5 @@ SceneItemHide="Ocultar '%1'"
OutputWarnings.NoTracksSelected="Debe seleccionar al menos una pista"
OutputWarnings.MultiTrackRecording="ADVERTENCIA: Ciertos formatos (como FLV) no admiten varias pistas por grabación"
+OutputWarnings.MP4Recording="ADVERTENCIA: Las grabaciones guardadas en MP4 será irrecuperables si el archivo no puede finalizarse (e.g. como resultado de BSODs, pérdidas de potencia, etcetera). Si quieres grabar varias pistas de audio utiliza MKV y reune la grabación a mp4 después de que termine (archivo-> Remux de grabaciones)"
diff --git a/UI/data/locale/et-EE.ini b/UI/data/locale/et-EE.ini
index 2c31217..8362469 100644
--- a/UI/data/locale/et-EE.ini
+++ b/UI/data/locale/et-EE.ini
@@ -48,10 +48,31 @@ Left="Vasakult"
Right="Paremalt"
Top="Ülalt"
Bottom="Alt"
+Reset="Lähtesta"
+Hours="Tundi"
+Minutes="Minutit"
+Seconds="Sekundit"
+Deprecated="Aegunud"
+ReplayBuffer="Taasesituse puhver"
+Import="Impordi"
+Export="Ekspordi"
+
+Updater.Title="Uus värskendus saadaval"
+Updater.Text="Uus värskendus on saadaval:"
+Updater.UpdateNow="Värskenda kohe"
+Updater.RemindMeLater="Tuleta mulle hiljem meelde"
+Updater.Skip="Jäta vahele versioon"
+Updater.Running.Title="Programm on hetkel aktiivne"
+Updater.Running.Text="Väljundid on hetkel aktiivsed, palun sulgege aktiivsed väljundid enne uuendamist"
+Updater.NoUpdatesAvailable.Title="Uusi värskendusi pole saadaval"
+Updater.NoUpdatesAvailable.Text="Värskendusi pole praegu saadaval"
+Updater.FailedToLaunch="Uuendaja käivitamine nurjus"
+Updater.GameCaptureActive.Title="Mängu hõive on aktiivne"
QuickTransitions.SwapScenes="Vaheta üleminekul eelvaade ja väljund"
QuickTransitions.SwapScenesTT="Vahetab pärast üleminekut eelvaate ja väljundi stseenid (kui väljundi esialgne stseen on veel olemas).\nEsialgsele stseenile tehtud muudatusi ei pöörata tagasi."
QuickTransitions.DuplicateScene="Tee stseenist koopia"
+QuickTransitions.EditProperties="Dubleeritud allikad"
QuickTransitions.HotkeyName="Valitud üleminek: %1"
Basic.AddTransition="Lisa seadistatav üleminek"
@@ -85,13 +106,19 @@ ConfirmExit.Text="OBS on hetkel aktiivne. Kõik voogedastused ja salvestused pea
ConfirmRemove.Title="Ümbernimetamise kinnitamine"
ConfirmRemove.Text="Kas soovid kindlasti eemaldada '$1'?"
+Output.StartStreamFailed="Voogedastuse alustamine nurjus"
+Output.StartRecordingFailed="Salvestamise alustamine nurjus"
+
Output.ConnectFail.Title="Ühendamine ei õnnestunud"
Output.ConnectFail.BadPath="Vigane rada või ühenduse URL. Palun veendu, et valitud sätted on õiged."
Output.ConnectFail.ConnectFailed="Serveriga ühendamine ebaõnnestus"
+Output.RecordError.Title="Salvestamise tõrge"
+LogReturnDialog.CopyURL="Kopeeri aadress"
+LicenseAgreement.IAgree="Nõustun"
LicenseAgreement.Exit="Välju"
Remux.SourceFile="OBS-i salvestus"
@@ -118,14 +145,20 @@ Basic.Scene="Stseen"
Basic.Main.PreviewConextMenu.Enable="Lülita eelvaade sisse"
+ScaleFiltering.Point="Punkt"
+VolControl.Properties="'%1' atribuudid"
+
Basic.Main.AddSceneDlg.Title="Stseeni lisamine"
Basic.Main.AddSceneDlg.Text="Sisesta stseeni nimi"
Basic.Main.DefaultSceneName.Text="Stseen %1"
+Basic.Main.AddSceneCollection.Title="Lisada stseeni kogumik"
+Basic.Main.AddSceneCollection.Text="Palun sisestage stseeni kogumiku nimi"
+Basic.Main.RenameSceneCollection.Title="Nimeta ümber stseeni kogumik"
AddProfile.Title="Profiili lisamine"
AddProfile.Text="Sisesta uue profiili nimi"
@@ -140,6 +173,9 @@ Basic.SourceSelect.AddExisting="Lisa olemasolev"
Basic.SourceSelect.AddVisible="Tee allikas nähtavaks"
Basic.PropertiesWindow="'%1' omadused"
+Basic.PropertiesWindow.AddFiles="Lisa failid"
+Basic.PropertiesWindow.AddDir="Lisa kataloog"
+Basic.PropertiesWindow.AddURL="Lisa tee/URL"
@@ -148,6 +184,7 @@ Basic.Filters="Filtrid"
Basic.Filters.AudioFilters="Helifiltrid"
Basic.Filters.AddFilter.Title="Filtri nimi"
+Basic.TransformWindow.Position="Asukoht"
Basic.TransformWindow.Rotation="Pööramine"
Basic.TransformWindow.Size="Suurus"
Basic.TransformWindow.Alignment="Joondamine"
@@ -187,27 +224,51 @@ Basic.MainMenu.File.Exit="Välju (&X)"
Basic.MainMenu.Edit="Muuda (&E)"
Basic.MainMenu.Edit.Undo="Võta tagasi (&U)"
+Basic.MainMenu.Edit.UndoAction="&Võta tagasi $1"
+Basic.MainMenu.Edit.Transform.Rotate90CW="Pööra 90 kraadi paremale"
+Basic.MainMenu.Edit.Transform.Rotate90CCW="Pööra 90 kraadi vasakule"
+Basic.MainMenu.Edit.Transform.Rotate180="Pööra 180 kraadi"
+Basic.MainMenu.Edit.Transform.FitToScreen="&Sobita ekraanile"
+Basic.MainMenu.Edit.Transform.StretchToScreen="&Venita ekraanile"
+Basic.MainMenu.Edit.Order="&Järjekord"
+Basic.MainMenu.Edit.Order.MoveUp="Liiguta &Üles"
+Basic.MainMenu.Edit.Order.MoveDown="Liiguta &Alla"
+Basic.MainMenu.Edit.Order.MoveToTop="Liiguta &Esimeseks"
+Basic.MainMenu.Edit.Order.MoveToBottom="Liiguta &Viimaseks"
+Basic.MainMenu.Edit.AdvAudio="&Täpsemad Heliatribuudid"
+Basic.MainMenu.View="&Vaade"
+Basic.MainMenu.View.Toolbars="&Tööriistaribad"
+Basic.MainMenu.View.SceneTransitions="S&tseeni üleminekud"
+Basic.MainMenu.View.StatusBar="&Olekuriba"
+Basic.MainMenu.SceneCollection="&Stseeni kogumik"
+Basic.MainMenu.Profile="&Profiil"
Basic.MainMenu.Help.Logs="&Logifailid"
Basic.MainMenu.Help.CheckForUpdates="Otsi värskendusi"
+Basic.Settings.General.Theme="Teema"
Basic.Settings.General.Language="Keel"
+Basic.Settings.General.Projectors="Projektorid"
Basic.Settings.Stream="Voogedastus"
Basic.Settings.Stream.StreamType="Voogedastuse tüüp"
Basic.Settings.Output="Väljund"
Basic.Settings.Output.Format="Salvestusvorming"
+Basic.Settings.Output.Encoder="Kodeerija"
Basic.Settings.Output.SelectDirectory="Vali salvestuskaust"
Basic.Settings.Output.Mode="Väljundrežiim"
Basic.Settings.Output.Mode.Simple="Lihtne"
Basic.Settings.Output.Mode.Adv="Täpsemad seaded"
Basic.Settings.Output.Simple.Encoder.Software="Tarkvara (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Riistvara (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Riistvara (AMD)"
+Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Riistvara (NVENC)"
+Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Tarkvara (x264 madal CPU kasutus, suurendab faili suurust)"
Basic.Settings.Output.Adv.AudioTrack="Helirada"
Basic.Settings.Output.Adv.Streaming="Voogedastus"
@@ -238,6 +299,8 @@ Basic.Settings.Video.Denominator="Nimetaja:"
Basic.Settings.Video.InvalidResolution="Eraldusvõime ei sobi. See peab olema kujul [width]x[height] (nt 1920x1080)"
+Basic.Settings.Audio.DesktopDevice="Töölaua heliseade"
+Basic.Settings.Audio.DesktopDevice2="Töölaua heliseade 2"
Basic.Settings.Advanced.Video.ColorRange.Partial="Osaline"
Basic.Settings.Advanced.Video.ColorRange.Full="Täielik"
diff --git a/UI/data/locale/eu-ES.ini b/UI/data/locale/eu-ES.ini
index d2ac30d..98208a6 100644
--- a/UI/data/locale/eu-ES.ini
+++ b/UI/data/locale/eu-ES.ini
@@ -49,6 +49,26 @@ Right="Eskuinean"
Top="Goian"
Bottom="Behean"
Reset="Berrezarri"
+Hours="ordu"
+Minutes="minutu"
+Seconds="segundo"
+Deprecated="Zaharkitua"
+ReplayBuffer="Erreprodukzio bufferra"
+Import="Inportatu"
+Export="Esportatu"
+
+Updater.Title="Eguneraketa berria eskuragarri"
+Updater.Text="Eguneraketa berri bat eskuragarri dago:"
+Updater.UpdateNow="Eguneratu orain"
+Updater.RemindMeLater="Gogoratu geroago"
+Updater.Skip="Baztertu bertsioa"
+Updater.Running.Title="Uneko programa aktiboa"
+Updater.Running.Text="Une honetan irteerak aktibo daude, itzali aktibo dauden irteerak eguneratzen saiatu aurretik"
+Updater.NoUpdatesAvailable.Title="Ez dago eguneraketarik eskuragarri"
+Updater.NoUpdatesAvailable.Text="Une honetan ez dago eguneraketarik eskuragarri"
+Updater.FailedToLaunch="Huts egin du eguneratzailea abiarazten"
+Updater.GameCaptureActive.Title="Jolasen kaptura aktiboa"
+Updater.GameCaptureActive.Text="Jolasen kapturaren liburutegia erabiltzen ari da. Itxi kapturatzen ari den jolasa/programa (edo berrabiarazi Windows) eta saiatu berriro."
QuickTransitions.SwapScenes="Trukatu Aurrebista/Irteera-eszenak trantsizioen ondoren"
QuickTransitions.SwapScenesTT="Trukatu aurrebistak eta irteera-eszenak trantsizioen ondoren (baldin eta irteerakoaren jatorrizkoa eszena badago).\n Honek ez du desegingo irteerakoaren jatorrizko eszenari egindako aldaketak."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Baieztatu kentzea"
ConfirmRemove.Text="Ziur zaude '$1' kendu nahi duzula?"
ConfirmRemove.TextMultiple="Seguru zaude %1 elementuak ezabatu nahi dituzula?"
+Output.StartStreamFailed="Huts egin du transmisioak"
+Output.StartRecordingFailed="Huts egin du grabazioak"
+Output.StartReplayFailed="Huts egin du erreprodukzio bufferrak"
+Output.StartFailedGeneric="Huts egin du irteeraren abioak. Begiratu erregistroa zehaztasunak ikusteko.\n\nOharra: NVENC edo AMD kodetzaileak erabiltzen ari bazara segurtatu haien kontrolatzaileak eguneratuta daudela."
+
Output.ConnectFail.Title="Huts egin du konektatzean"
Output.ConnectFail.BadPath="Helburu edo konexio-URL okerra. Egiaztatu zure ezarpenak baliozkoak direla baieztatzeko."
Output.ConnectFail.ConnectFailed="Huts egin du zerbitzariarekin konektatzean"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Ez dago nahiko tokirik diskoan"
Output.RecordNoSpace.Msg="Ez dago nahikoa tokirik diskoan grabatzen jarraitzeko."
Output.RecordError.Title="Grabazio akatsa"
Output.RecordError.Msg="Zehaztugabeko akats bat gertatu da grabatzerakoan."
+Output.ReplayBuffer.NoHotkey.Title="Laster tekla ezarri gabe!"
+Output.ReplayBuffer.NoHotkey.Msg="Ez da ezarri gordetzeko laster teklarik erreprodukzio bufferrerako. Ezarri \"Gorde\" laster tekla erreprodukzio bufferrak gordetzeko."
Output.BadPath.Title="Fitxategi-bide okerra"
Output.BadPath.Text="Ezarritako fitxategiaren irteera-bidea baliogabea da. Egiaztatu zure ezarpenak baieztatzeko baliozko fitxategi-bidea ezarri dela."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Goiko eremua lehenik"
Deinterlacing.BottomFieldFirst="Beheko eremua lehenik"
+VolControl.SliderUnmuted="Bolumen graduatzailea '%1'-rentzat: %2"
+VolControl.SliderMuted="Bolumen graduatzailea '%1'-rentzat: %2 (une honetan mutu)"
+VolControl.Mute="Mututu '%1'"
+VolControl.Properties="'%1'-ren ezaugarriak"
+
Basic.Main.AddSceneDlg.Title="Gehitu eszena"
Basic.Main.AddSceneDlg.Text="Sartu eszenaren izena"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Eszenak"
Basic.Main.Sources="Iturburuak"
Basic.Main.Connecting="Konektatzen..."
Basic.Main.StartRecording="Hasi grabazioa"
+Basic.Main.StartReplayBuffer="Abiatu erreprodukzio bufferra"
Basic.Main.StartStreaming="Hasi transmisioa"
Basic.Main.StopRecording="Gelditu grabazioa"
Basic.Main.StoppingRecording="Grabazioa gelditzen..."
+Basic.Main.StopReplayBuffer="Gelditu erreprodukzio buferra"
+Basic.Main.StoppingReplayBuffer="Erreprodukzio bufferra gelditzen..."
Basic.Main.StopStreaming="Gelditu transmisioa"
Basic.Main.StoppingStreaming="Transmisioa gelditzen..."
Basic.Main.ForceStopStreaming="Gelditu transmisioa (baztertu atzerapena)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Berregin"
Basic.MainMenu.Edit.UndoAction="&Desegin $1"
Basic.MainMenu.Edit.RedoAction="&Berregin $1"
Basic.MainMenu.Edit.LockPreview="Blokeatu aurrebista"
+Basic.MainMenu.Edit.Scale="Aurrebistaren eskala"
+Basic.MainMenu.Edit.Scale.Window="Eskalatu leihora"
+Basic.MainMenu.Edit.Scale.Canvas="Oihala (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Irteera (%1x%2)"
Basic.MainMenu.Edit.Transform="&Eraldatu"
Basic.MainMenu.Edit.Transform.EditTransform="E&ditatu eraldaketa..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Kopiatu eraldaketa"
+Basic.MainMenu.Edit.Transform.PasteTransform="Itsatsi eraldaketa"
Basic.MainMenu.Edit.Transform.ResetTransform="&Berrezarri eraldaketa"
Basic.MainMenu.Edit.Transform.Rotate90CW="Biratu 90 gradu erlojuaren norabidean"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Biratu 90 gradu erlojuaren kontrako norabidean"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="Egoera-barra"
Basic.MainMenu.SceneCollection="&Eszena-bilduma"
Basic.MainMenu.Profile="&Profila"
+Basic.MainMenu.Profile.Import="Inportatu profila"
+Basic.MainMenu.Profile.Export="Esportatu profila"
+Basic.MainMenu.SceneCollection.Import="Inportatu eszena bilduma"
+Basic.MainMenu.SceneCollection.Export="Esportatu eszena bilduma"
+Basic.MainMenu.Profile.Exists="Profila lehendik ere badago"
+Basic.MainMenu.SceneCollection.Exists="Eszena bilduma lehendik ere badago"
Basic.MainMenu.Tools="&Tresnak"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Gordegabeko aldaketak dituzu. Gorde aldaketak?"
Basic.Settings.General="Orokorra"
Basic.Settings.General.Theme="Gaia"
Basic.Settings.General.Language="Hizkuntza"
+Basic.Settings.General.EnableAutoUpdates="Abiaraztean begiratu automatikoki eguneraketarik ba ote dagoen"
Basic.Settings.General.WarnBeforeStartingStream="Erakutsi baieztapen elkarrizketa transmisioak hasterakoan"
-Basic.Settings.General.WarnBeforeStoppingStream="Erakutsi baieztapen elkarrizketa transmisioak gelditzerakoan"
+Basic.Settings.General.WarnBeforeStoppingStream="Erakutsi baieztapen elkarrizketa transmisioak gelditzean"
+Basic.Settings.General.Projectors="Projektoreak"
Basic.Settings.General.HideProjectorCursor="Ezkutatu kurtsorea proiekzioetan"
Basic.Settings.General.ProjectorAlwaysOnTop="Proiektoreak beti gainean"
Basic.Settings.General.Snapping="Iturburuaren lerrokatzearen doitzea"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Doitu iturburuak beste iturburuetara"
Basic.Settings.General.SnapDistance="Doitu sentikortasuna"
Basic.Settings.General.RecordWhenStreaming="Grabatu automatikoki transmisioa egitean"
Basic.Settings.General.KeepRecordingWhenStreamStops="Mantendu grabazioa transmisioa gelditzean"
-Basic.Settings.General.SysTrayEnabled="Gaitu sistemaren erretiluko ikonoa"
+Basic.Settings.General.ReplayBufferWhileStreaming="Hasi erreprodukzio bufferra automatikoki transmititzean"
+Basic.Settings.General.KeepReplayBufferStreamStops="Mantendu erreprodukzio bufferra aktiboa transmisioa gelditzean"
+Basic.Settings.General.SysTray="Sistemaren erretilua"
Basic.Settings.General.SysTrayWhenStarted="Minimizatu sistemaren erretilura hastean"
+Basic.Settings.General.SystemTrayHideMinimize="Minimizatu beti sistemaren erretilura ataza barrara egin ordez"
+Basic.Settings.General.SaveProjectors="Gorde proiekzioak irtetean"
Basic.Settings.Stream="Transmisioa"
Basic.Settings.Stream.StreamType="Transmisio-mota"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Irteera-modua"
Basic.Settings.Output.Mode.Simple="Arrunta"
Basic.Settings.Output.Mode.Adv="Aurreratua"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg Irteera"
+Basic.Settings.Output.UseReplayBuffer="Gaitu erreprodukzio bufferra"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Erreprodukzioaren gehienezko denbora (segundotan)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Gehienezko memoria (megabytetan)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Ustezko memoria erabilera: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Ezin da kalkulatu memoria erabilera. Ezarri gehienezko memoria."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Oharra: Aseguratu bufferraren erreprodukziorako laster tekla bat ezarri duzula laster teklen atalean)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Erreprodukzio bufferraren fitxategi aurrizkia"
+Basic.Settings.Output.ReplayBuffer.Suffix="Atzizkia"
Basic.Settings.Output.Simple.SavePath="Grabazio-bidea"
Basic.Settings.Output.Simple.RecordingQuality="Grabazio-kalitatea"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Transmisioaren berdina"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Galerarik gabeko kalitateaz oh
Basic.Settings.Output.Simple.Warn.MultipleQSV="Kontuz: Ezin dituzu QSV kodeatzaile ugari bananduta erabili aldiberean jariotu eta grabatzerakoan. Aldiberean jariotu eta grabatzea nahi baduzu, mesedez aldatu bietako bat, grabaketa kodeatzailea edo jariotze kodeatzailea."
Basic.Settings.Output.Simple.Encoder.Software="Softwarea (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardwarea (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardwarea (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardwarea (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Softwarea (x264 PUZ erabilpen apaleko aurre-ezarpena, fitxategiaren tamaina handitzen du)"
Basic.Settings.Output.VideoBitrate="Bideo bit-emaria"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="1 pista"
Basic.Settings.Output.Adv.Audio.Track2="2 pista"
Basic.Settings.Output.Adv.Audio.Track3="3 pista"
Basic.Settings.Output.Adv.Audio.Track4="4 pista"
+Basic.Settings.Output.Adv.Audio.Track5="5. pista"
+Basic.Settings.Output.Adv.Audio.Track6="6. pista"
Basic.Settings.Output.Adv.Recording="Grabatzen"
Basic.Settings.Output.Adv.Recording.Type="Mota"
@@ -417,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Bideo kodetzailearen ezarpena
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio kodetzailea"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audio kodetzailearen ezarpenak (egonez gero)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Bihurtzailearen ezarpenak (egonez gero)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Gako-fotogramen tartea (fotogramak)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Erakutsi kodek guztiak (bateragarriak ez balira ere)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV kolore-espazioa"
Basic.Settings.Advanced.Video.ColorRange="YUV kolore-barrutia"
Basic.Settings.Advanced.Video.ColorRange.Partial="Partziala"
Basic.Settings.Advanced.Video.ColorRange.Full="Osoa"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Audioa kontrolatzeko gailua"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Lehenetsia"
Basic.Settings.Advanced.StreamDelay="Taansmisio-atzerapena"
Basic.Settings.Advanced.StreamDelay.Duration="Iraupena (segundoak)"
Basic.Settings.Advanced.StreamDelay.Preserve="Mantendu ebaketa puntua (handitu atzerapena) birkonektatzean"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimatutako memoria erabilpena: %1 MB"
Basic.Settings.Advanced.Network="Sarea"
Basic.Settings.Advanced.Network.BindToIP="IP bidez lotu"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Gaitu sare kode berria"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Latentzia txikiko modua"
Basic.AdvAudio="Audio propietate aurreratuak"
Basic.AdvAudio.Name="Izena"
@@ -483,15 +553,15 @@ Basic.AdvAudio.Volume="Bolumena (%)"
Basic.AdvAudio.Mono="Nahasketa monora murriztu"
Basic.AdvAudio.Panning="Panoramika"
Basic.AdvAudio.SyncOffset="Sinkronizazioaren desplazamendua (ms)"
+Basic.AdvAudio.Monitoring="Adioaren kontrola"
+Basic.AdvAudio.Monitoring.None="Audioa itzalita"
+Basic.AdvAudio.Monitoring.MonitorOnly="Kontrola bakarrik (irteera mututua)"
+Basic.AdvAudio.Monitoring.Both="Kontrola eta irteera"
Basic.AdvAudio.AudioTracks="Pistak"
Basic.Settings.Hotkeys="Laster-teklak"
Basic.Settings.Hotkeys.Pair="'%1'-rekin egindako tekla konbinazioek txandakatze moduan jokatzen dute"
-Basic.Hotkeys.StartStreaming="Hasi transmisioa"
-Basic.Hotkeys.StopStreaming="Gelditu transmisioa"
-Basic.Hotkeys.StartRecording="Hasi Grabazioa"
-Basic.Hotkeys.StopRecording="Gelditu grabazioa"
Basic.Hotkeys.SelectScene="Aldatu eszenara"
Basic.SystemTray.Show="Erakutsi"
@@ -545,4 +615,5 @@ SceneItemHide="Ezkutatu '%1'"
OutputWarnings.NoTracksSelected="Gutxienez pista bat hautatu behar duzu"
OutputWarnings.MultiTrackRecording="Oharra: Zenbait formatuk (esaterako FLV-k) ez ditu pista anitzak onartzen grabazioan"
+OutputWarnings.MP4Recording="Kontuz: MP4 formatuz gordetako grabazioak izan daitezke berreskuraezinak fitxategia ezin bada bukatu (esate baterako energia etenagatik). Hainbat audio pista grabatu nahi baduzu erabil dezakezu MKV formatua eta mp4 bihurtu grabazioa bukatu ondoren (Fitxategia->Bihurtu grabazioak)"
diff --git a/UI/data/locale/fi-FI.ini b/UI/data/locale/fi-FI.ini
index b8c5ff7..cb8d84d 100644
--- a/UI/data/locale/fi-FI.ini
+++ b/UI/data/locale/fi-FI.ini
@@ -49,6 +49,26 @@ Right="Oikea"
Top="Ylhäältä"
Bottom="Alhaalta"
Reset="Palauta"
+Hours="Tuntia"
+Minutes="Minuuttia"
+Seconds="Sekuntia"
+Deprecated="Vanhentunut"
+ReplayBuffer="Toistopuskuri"
+Import="Tuo"
+Export="Vie"
+
+Updater.Title="Uusi päivitys on saatavilla"
+Updater.Text="Uusi päivitys on saatavilla:"
+Updater.UpdateNow="Päivitä nyt"
+Updater.RemindMeLater="Muistuta myöhemmin"
+Updater.Skip="Ohita versio"
+Updater.Running.Title="Ohjelma on käytössä"
+Updater.Running.Text="Tallentaminen/lähetys on aktiivinen. Sulje kaikki ulostulo ennen päivityksen jatkamista"
+Updater.NoUpdatesAvailable.Title="Päivityksiä ei ole saatavilla"
+Updater.NoUpdatesAvailable.Text="Päivityksiä ei ole tällä hetkellä saatavilla"
+Updater.FailedToLaunch="Päivittäjän käynnistäminen epäonnistui"
+Updater.GameCaptureActive.Title="Game capture on aktiivinen"
+Updater.GameCaptureActive.Text="Game capture -kirjasto on yhä käytössä. Sulje kaikki pelit/ohjelmat, joita on kaapattu tai käynnistä tietokone uudelleen."
QuickTransitions.SwapScenes="Vaihda esikatselu- ja ulostulo-skenet siirtymän jälkeen"
QuickTransitions.SwapScenesTT="Vaihda esikatselu- ja ulostulo-skenet siirtymän jälkeen (jos ulostulon alkuperäinen skene on yhä olemassa).\nTämä ei peruuta muutoksia joita on tehty alkuperäiseen skeneen."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Vahvista poisto"
ConfirmRemove.Text="Haluatko varmasti poistaa '$1'?"
ConfirmRemove.TextMultiple="Haluatko varmasti poistaa %1 kohdetta?"
+Output.StartStreamFailed="Lähetyksen aloittaminen epäonnistui"
+Output.StartRecordingFailed="Tallennuksen aloittaminen epäonnistui"
+Output.StartReplayFailed="Toistopuskurin käynnistäminen epäonnistui"
+Output.StartFailedGeneric="Ulostulon käynnistäminen epäonnistui. Tarkista loki lisätietoja varten.\n\nHuomio: Jos käytät NVENC tai AMD -enkoodereita, varmista, että näytönohjaimen ajurit on päivitetty ajantasalle."
+
Output.ConnectFail.Title="Yhdistäminen epäonnistui"
Output.ConnectFail.BadPath="Viallinen polku tai yhteysosoite. Tarkista, että asetuksesi ovat kunnossa."
Output.ConnectFail.ConnectFailed="Palvelimelle yhdistäminen epäonnistui"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Liian vähän levytilaa"
Output.RecordNoSpace.Msg="Levytilaa ei ole riittävästi tallennuksen jatkamiseen."
Output.RecordError.Title="Tallennusvirhe"
Output.RecordError.Msg="Tallennuksen aikana tapahtui määrittelemätön virhe."
+Output.ReplayBuffer.NoHotkey.Title="Pikanäppäintä ei ole asetettu!"
+Output.ReplayBuffer.NoHotkey.Msg="Tallennuksen pikanäppäintä ei ole asetettu toistopuskurille. Aseta \"Tallenna\"-pikanäppäin tallentaaksesi uusinnat."
Output.BadPath.Title="Viallinen tiedostopolku"
Output.BadPath.Text="Asetettu tiedostopolku on viallinen. Tarkista asetuksistasi, että tiedostopolku on asetettu oikein."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Ylin kenttä ensin"
Deinterlacing.BottomFieldFirst="Alin kenttä ensin"
+VolControl.SliderUnmuted="Äänenvoimakkuus \"%1\": %2"
+VolControl.SliderMuted="Äänenvoimakkuus \"%1\": %2 (mykistetty)"
+VolControl.Mute="Mykistä %1"
+VolControl.Properties="Ominaisuudet %1:lle"
+
Basic.Main.AddSceneDlg.Title="Lisää skene"
Basic.Main.AddSceneDlg.Text="Aseta skenen nimi"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Skenet"
Basic.Main.Sources="Lähteet"
Basic.Main.Connecting="Yhdistetään..."
Basic.Main.StartRecording="Aloita tallennus"
+Basic.Main.StartReplayBuffer="Käynnistä toistopuskuri"
Basic.Main.StartStreaming="Aloita lähetys"
Basic.Main.StopRecording="Pysäytä tallennus"
Basic.Main.StoppingRecording="Pysäytetään tallennusta..."
+Basic.Main.StopReplayBuffer="Pysäytä toistopuskuri"
+Basic.Main.StoppingReplayBuffer="Pysäytetään toistopuskuri..."
Basic.Main.StopStreaming="Pysäytä lähetys"
Basic.Main.StoppingStreaming="Pysäytetään lähetystä..."
Basic.Main.ForceStopStreaming="Lopeta lähetys (ohita viive)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Tee uudelleen"
Basic.MainMenu.Edit.UndoAction="Kum&oa $1"
Basic.MainMenu.Edit.RedoAction="T&ee uudelleen $1"
Basic.MainMenu.Edit.LockPreview="&Lukitse esikatselu"
+Basic.MainMenu.Edit.Scale="Esikatselun &skaalaus"
+Basic.MainMenu.Edit.Scale.Window="Skaalaa ikkunaan"
+Basic.MainMenu.Edit.Scale.Canvas="Kanvaasi (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Ulostulo (%1x%2)"
Basic.MainMenu.Edit.Transform="Muu&nna"
Basic.MainMenu.Edit.Transform.EditTransform="M&uokkaa muunnosta..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Kopioi muunnos"
+Basic.MainMenu.Edit.Transform.PasteTransform="Liitä muunnos"
Basic.MainMenu.Edit.Transform.ResetTransform="&Nollaa muunnos"
Basic.MainMenu.Edit.Transform.Rotate90CW="Kierrä 90 astetta myötäpäivään"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Kierrä 90 astetta vastapäivään"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Tilapalkki"
Basic.MainMenu.SceneCollection="&Skene-kokoelma"
Basic.MainMenu.Profile="&Profiili"
+Basic.MainMenu.Profile.Import="Tuo profiili"
+Basic.MainMenu.Profile.Export="Vie profiili"
+Basic.MainMenu.SceneCollection.Import="Tuo skene-kokoelma"
+Basic.MainMenu.SceneCollection.Export="Vie skene-kokoelma"
+Basic.MainMenu.Profile.Exists="Profiili on jo olemassa"
+Basic.MainMenu.SceneCollection.Exists="Skene-kokoelma on jo olemassa"
Basic.MainMenu.Tools="T&yökalut"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Sinulla on tallentamattomia muutoksia. Tallennetaanko?"
Basic.Settings.General="Yleiset"
Basic.Settings.General.Theme="Teema"
Basic.Settings.General.Language="Kieli"
+Basic.Settings.General.EnableAutoUpdates="Tarkista päivitykset automaattisesti käynnistäessä"
Basic.Settings.General.WarnBeforeStartingStream="Näytä varmistus-ikkuna kun lähetys aloitetaan"
Basic.Settings.General.WarnBeforeStoppingStream="Näytä varmistus-ikkuna kun lähetys pysäytetään"
+Basic.Settings.General.Projectors="Peilaukset"
Basic.Settings.General.HideProjectorCursor="Piilota osoitin peilattaessa"
Basic.Settings.General.ProjectorAlwaysOnTop="Pidä peilatut esikatselut aina päällimmäisenä"
Basic.Settings.General.Snapping="Lähteiden kiinnitys"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Kiinnitä lähteitä muihin lähteisiin"
Basic.Settings.General.SnapDistance="Kiinnityksen herkkyys"
Basic.Settings.General.RecordWhenStreaming="Tallenna automaattisesti kun lähetetään"
Basic.Settings.General.KeepRecordingWhenStreamStops="Jatka tallennusta lähetyksen loputtua"
-Basic.Settings.General.SysTrayEnabled="Ota järjestelmäkuvake käyttöön"
+Basic.Settings.General.ReplayBufferWhileStreaming="Käynnistä toistopuskuri automaattisesti lähetettäessä"
+Basic.Settings.General.KeepReplayBufferStreamStops="Pidä toistopuskuri käytössä kun lähetys loppuu"
+Basic.Settings.General.SysTray="Ilmaisinalue"
Basic.Settings.General.SysTrayWhenStarted="Pienennä ilmaisinalueelle käynnistyessä"
+Basic.Settings.General.SystemTrayHideMinimize="Pienennä aina tilapalkkiin tehtäväpalkin sijaan"
+Basic.Settings.General.SaveProjectors="Tallenna peilaus poistuessa"
Basic.Settings.Stream="Lähetys"
Basic.Settings.Stream.StreamType="Lähetystyyppi"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Ulostulon tila"
Basic.Settings.Output.Mode.Simple="Yksinkertainen"
Basic.Settings.Output.Mode.Adv="Kehittynyt"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg ulostulo"
+Basic.Settings.Output.UseReplayBuffer="Ota toistopuskuri käyttöön"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Uusinnan pisin aika (Sekunteina)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Muistiraja (Megatavuja)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Arvioitu muistinkäyttö: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Muistin käyttöä ei voida arvioida. Valitse muistiraja."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Huomio: Varmista että toistopuskurin pikanäppäin on asetettuna asetuksista)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Toistopuskurin tiedostonimen etuliite"
+Basic.Settings.Output.ReplayBuffer.Suffix="Pääte"
Basic.Settings.Output.Simple.SavePath="Tallennuksen polku"
Basic.Settings.Output.Simple.RecordingQuality="Tallennuksen laatu"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Sama kuin lähetyksessä"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Häviötön laatu!"
Basic.Settings.Output.Simple.Warn.MultipleQSV="Varoitus: Et voi käyttää useampaa QSV-enkooderia lähettäessä ja tallentaessa samaan aikaan. Jos haluat tehdä molempia yhtä aikaa, vaihda lähetys tai tallennus-enkooderi."
Basic.Settings.Output.Simple.Encoder.Software="Ohjelmistopohjainen (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Laitteistopohjainen (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Laitteisto (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Laitteistopohjainen (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Ohjelmistopohjainen (x264 matala CPU-käyttö, lisää tiedostokokoa)"
Basic.Settings.Output.VideoBitrate="Kuvan bitrate"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Raita 1"
Basic.Settings.Output.Adv.Audio.Track2="Raita 2"
Basic.Settings.Output.Adv.Audio.Track3="Raita 3"
Basic.Settings.Output.Adv.Audio.Track4="Raita 4"
+Basic.Settings.Output.Adv.Audio.Track5="Raita 5"
+Basic.Settings.Output.Adv.Audio.Track6="Raita 6"
Basic.Settings.Output.Adv.Recording="Tallennus"
Basic.Settings.Output.Adv.Recording.Type="Tyyppi"
@@ -417,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Videoenkooderin asetukset"
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Äänienkooderi"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Äänienkooderin asetukset"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muunnon asetukset"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Keyframe-väli (frameina)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Näytä kaikki koodekit (myös mahdollisesti yhteensopimattomat)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV väriavaruus"
Basic.Settings.Advanced.Video.ColorRange="YUV värialue"
Basic.Settings.Advanced.Video.ColorRange.Partial="Osittainen"
Basic.Settings.Advanced.Video.ColorRange.Full="Täysi"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Äänen monitorointilaite"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Oletusarvo"
Basic.Settings.Advanced.StreamDelay="Lähetyksen viive"
Basic.Settings.Advanced.StreamDelay.Duration="Kesto (sekunteina)"
Basic.Settings.Advanced.StreamDelay.Preserve="Säilytä katkaisupiste (lisää viivettä) uudelleenyhdistettäessä"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Arvioitu muistinkäyttö: %1 MB"
Basic.Settings.Advanced.Network="Verkko"
Basic.Settings.Advanced.Network.BindToIP="Liitä IP:seen"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Käytä uutta verkkokoodia"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Alhaisen latenssin tila"
Basic.AdvAudio="Äänen lisäominaisuudet"
Basic.AdvAudio.Name="Nimi"
@@ -483,15 +553,15 @@ Basic.AdvAudio.Volume="Äänenvoimakkuus (%)"
Basic.AdvAudio.Mono="Miksaa yksikanavaiseksi"
Basic.AdvAudio.Panning="Balanssi"
Basic.AdvAudio.SyncOffset="Synkronoinnin viivästys (ms)"
+Basic.AdvAudio.Monitoring="Äänen monitorointi"
+Basic.AdvAudio.Monitoring.None="Monitorointi pois"
+Basic.AdvAudio.Monitoring.MonitorOnly="Vain monitorointi (hiljennä ulostulo)"
+Basic.AdvAudio.Monitoring.Both="Monitorointi ja ulostulo"
Basic.AdvAudio.AudioTracks="Raidat"
Basic.Settings.Hotkeys="Pikanäppäimet"
Basic.Settings.Hotkeys.Pair="Yhteiset näppäinyhdistelmät '%1':n kanssa toimivat 'togglena'"
-Basic.Hotkeys.StartStreaming="Aloita lähetys"
-Basic.Hotkeys.StopStreaming="Pysäytä lähetys"
-Basic.Hotkeys.StartRecording="Aloita tallennus"
-Basic.Hotkeys.StopRecording="Pysäytä tallennus"
Basic.Hotkeys.SelectScene="Vaihda skeneen"
Basic.SystemTray.Show="Näytä"
@@ -545,4 +615,5 @@ SceneItemHide="Piilota '%1'"
OutputWarnings.NoTracksSelected="Sinun täytyy valita ainakin yksi raita"
OutputWarnings.MultiTrackRecording="Varoitus: Jotkin muodot (kuten FLV), eivät tue useampaa raitaa per tallennus"
+OutputWarnings.MP4Recording="Varoitus: MP4-muotoon tallentaessa tiedostoista tulee lukukelvottomia, mikäli niitä ei voi viimeistellä. (esim. johtuen BSOD:sta, sähkökatkosta jne.) Jos haluat tallentaa useampaa ääniraitaa, kannattaa käyttää MKV-muotoa ja muuntaa jälkikäteen MP4:ksi. (Tiedosto->Muunna tallenne)"
diff --git a/UI/data/locale/fr-FR.ini b/UI/data/locale/fr-FR.ini
index 781e993..fc438bf 100644
--- a/UI/data/locale/fr-FR.ini
+++ b/UI/data/locale/fr-FR.ini
@@ -27,7 +27,7 @@ Mixer="Mixage audio"
Browse="Parcourir"
Mono="Mono"
Stereo="Stéréo"
-DroppedFrames="Images Perdues %1 (%2%)"
+DroppedFrames="Images perdues : %1 (%2%)"
PreviewProjector="Projecteur plein écran (aperçu)"
SceneProjector="Projecteur plein écran (scène)"
SourceProjector="Projecteur plein écran (source)"
@@ -49,6 +49,26 @@ Right="À droite"
Top="En haut"
Bottom="En bas"
Reset="Réinitialiser"
+Hours="Heures"
+Minutes="Minutes"
+Seconds="Secondes"
+Deprecated="Obsolète"
+ReplayBuffer="Tampon de relecture"
+Import="Importer"
+Export="Exporter"
+
+Updater.Title="Nouvelle mise à jour disponible"
+Updater.Text="Une nouvelle mise à jour est disponible :"
+Updater.UpdateNow="Mettre à jour maintenant"
+Updater.RemindMeLater="Me le rappeler ultérieurement"
+Updater.Skip="Ignorer la version"
+Updater.Running.Title="Programme actuellement en cours d’exécution"
+Updater.Running.Text="Des sorties sont actuellement actives, veuillez fermer toutes les sorties actives avant d'essayer de mettre à jour"
+Updater.NoUpdatesAvailable.Title="Aucune mise à jour disponible"
+Updater.NoUpdatesAvailable.Text="Aucune mise à jour n’est actuellement disponible"
+Updater.FailedToLaunch="Impossible de démarrer la mise à jour"
+Updater.GameCaptureActive.Title="Capture de jeu active"
+Updater.GameCaptureActive.Text="La bibliothèque « hook » de capture de jeu est actuellement active. Veuillez fermer tous les jeux/programmes en cours de capture (ou redémarrez Windows) et réessayez."
QuickTransitions.SwapScenes="Permuter les scènes d'aperçu et de sortie après la transition"
QuickTransitions.SwapScenesTT="Permute les scènes d'aperçu et de sortie après la transition (si la scène d'origine de la sortie existe toujours). \nCela n'annulera pas les modifications qui auront pu être faites sur la scène d'origine de la sortie."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Confirmer la suppression"
ConfirmRemove.Text="Êtes-vous sûr de vouloir supprimer « $1 » ?"
ConfirmRemove.TextMultiple="Voulez-vous vraiment supprimer %1 éléments ?"
+Output.StartStreamFailed="Impossible de démarrer le streaming"
+Output.StartRecordingFailed="Impossible de démarrer l'enregistrement"
+Output.StartReplayFailed="Impossible de démarrer le tampon de relecture"
+Output.StartFailedGeneric="Le démarrage de la sortie a échoué. Veuillez consulter le journal pour plus de détails.\n\nRemarque : si vous utilisez les encodeurs NVENC ou AMD, assurez-vous que vos pilotes vidéo soient à jour."
+
Output.ConnectFail.Title="Échec de la connexion"
Output.ConnectFail.BadPath="Adresse de connexion ou chemin invalide. Veuillez vérifier vos paramètres afin de confirmer leur validité."
Output.ConnectFail.ConnectFailed="Échec de la connexion au serveur"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Espace disque insuffisant"
Output.RecordNoSpace.Msg="Il n'y a pas suffisamment d'espace disque pour continuer l'enregistrement."
Output.RecordError.Title="Erreur d'enregistrement"
Output.RecordError.Msg="Une erreur non spécifiée s'est produite lors de l'enregistrement."
+Output.ReplayBuffer.NoHotkey.Title="Aucun raccourci clavier défini !"
+Output.ReplayBuffer.NoHotkey.Msg="Aucun raccourci clavier défini pour le tampon de relecture. Veuillez en définir un pour utiliser cette fonction."
Output.BadPath.Title="Chemin d'accès au fichier incorrect"
Output.BadPath.Text="Le chemin configuré pour le flux sortant est invalide. Veuillez vérifier vos paramètres pour confirmer la présence d'un chemin valide."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Champ du haut prioritaire"
Deinterlacing.BottomFieldFirst="Champ du bas prioritaire"
+VolControl.SliderUnmuted="Curseur de volume pour « %1 » : %2"
+VolControl.SliderMuted="Curseur de volume pour « %1 » : %2 (actuellement désactivé)"
+VolControl.Mute="Muet '%1'"
+VolControl.Properties="Propriétés pour '%1'"
+
Basic.Main.AddSceneDlg.Title="Ajouter une scène"
Basic.Main.AddSceneDlg.Text="Veuillez entrer le nom de la scène"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Scènes"
Basic.Main.Sources="Sources"
Basic.Main.Connecting="Connexion en cours..."
Basic.Main.StartRecording="Démarrer l'enregistrement"
+Basic.Main.StartReplayBuffer="Démarrer le tampon de relecture"
Basic.Main.StartStreaming="Commencer le streaming"
Basic.Main.StopRecording="Arrêter l'enregistrement"
Basic.Main.StoppingRecording="Arrêt de l'enregistrement..."
+Basic.Main.StopReplayBuffer="Arrêter le tampon de relecture"
+Basic.Main.StoppingReplayBuffer="Arrêt du tampon de relecture..."
Basic.Main.StopStreaming="Arrêter le streaming"
Basic.Main.StoppingStreaming="Arrêt du stream..."
Basic.Main.ForceStopStreaming="Arrêter le streaming (annule le retard)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Rétablir"
Basic.MainMenu.Edit.UndoAction="&Annuler $1"
Basic.MainMenu.Edit.RedoAction="&Rétablir $1"
Basic.MainMenu.Edit.LockPreview="Verrouiller la prévisualisation"
+Basic.MainMenu.Edit.Scale="Mi&se à l'échelle de l'aperçu"
+Basic.MainMenu.Edit.Scale.Window="Adapter à la fenêtre"
+Basic.MainMenu.Edit.Scale.Canvas="Canvas (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Sortie (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformer"
Basic.MainMenu.Edit.Transform.EditTransform="Éditer la transformation..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Copier la transformation"
+Basic.MainMenu.Edit.Transform.PasteTransform="Coller la transformation"
Basic.MainMenu.Edit.Transform.ResetTransform="Réinitialiser la transformation"
Basic.MainMenu.Edit.Transform.Rotate90CW="Rotation de 90° sens horaire"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotation de 90° sens antihoraire"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Barre d'état"
Basic.MainMenu.SceneCollection="Collection de &scènes"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Importer un profil"
+Basic.MainMenu.Profile.Export="Exporter un profil"
+Basic.MainMenu.SceneCollection.Import="Importer une collection de scènes"
+Basic.MainMenu.SceneCollection.Export="Exporter une collection de scènes"
+Basic.MainMenu.Profile.Exists="Ce profil existe déjà"
+Basic.MainMenu.SceneCollection.Exists="Cette collection de scène existe déjà"
Basic.MainMenu.Tools="Outils"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Vous avez des modifications non enregistrées. Voulez-vo
Basic.Settings.General="Général"
Basic.Settings.General.Theme="Thème"
Basic.Settings.General.Language="Langue"
+Basic.Settings.General.EnableAutoUpdates="Vérifier automatiquement les mises à jour au démarrage"
Basic.Settings.General.WarnBeforeStartingStream="Afficher une boîte de dialogue de confirmation au démarrage d'un stream"
Basic.Settings.General.WarnBeforeStoppingStream="Afficher une boîte de dialogue de confirmation à l'arrêt d'un stream"
+Basic.Settings.General.Projectors="Projecteurs"
Basic.Settings.General.HideProjectorCursor="Cacher le curseur sur les projecteurs"
Basic.Settings.General.ProjectorAlwaysOnTop="Projecteurs toujours au premier plan"
Basic.Settings.General.Snapping="Déclenchement d'alignement des sources"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Déclencher avec d'autres sources"
Basic.Settings.General.SnapDistance="Sensibilité du déclenchement"
Basic.Settings.General.RecordWhenStreaming="Enregistrer automatiquement lors d'un stream"
Basic.Settings.General.KeepRecordingWhenStreamStops="Continuer à enregistrer lorsque le stream s’arrête"
-Basic.Settings.General.SysTrayEnabled="Afficher une icône dans la zone de notification"
+Basic.Settings.General.ReplayBufferWhileStreaming="Démarrer automatiquement le tampon de relecture lors d'un stream"
+Basic.Settings.General.KeepReplayBufferStreamStops="Garder le tampon de relecture actif lors de l'arrêt du stream"
+Basic.Settings.General.SysTray="Zone de notifications"
Basic.Settings.General.SysTrayWhenStarted="Réduire dans la zone de notification dès le démarrage"
+Basic.Settings.General.SystemTrayHideMinimize="Toujours réduire dans la zone de notification au lieu de la barre des tâches"
+Basic.Settings.General.SaveProjectors="Enregistrer les projecteurs en quittant"
Basic.Settings.Stream="Flux"
Basic.Settings.Stream.StreamType="Type de diffusion"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Mode de sortie"
Basic.Settings.Output.Mode.Simple="Simple"
Basic.Settings.Output.Mode.Adv="Avancé"
Basic.Settings.Output.Mode.FFmpeg="Sortie FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Activer le tampon de relecture"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Temps de relecture maximal (secondes)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Mémoire maximum (mégaoctets)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Estimation de la mémoire utilisée : %1 Mo"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Impossible d'estimer l'utilisation de la mémoire. Veuillez définir une limite de mémoire maximale."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Remarque : veillez à définir un raccourci clavier pour le tampon de relecture dans la section des raccourcis clavier)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Nom du fichier du tampon commençant par"
+Basic.Settings.Output.ReplayBuffer.Suffix="Finissant par"
Basic.Settings.Output.Simple.SavePath="Chemin d'accès de l'enregistrement"
Basic.Settings.Output.Simple.RecordingQuality="Qualité d'enregistrement"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Identique au stream"
@@ -391,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Piste 1"
Basic.Settings.Output.Adv.Audio.Track2="Piste 2"
Basic.Settings.Output.Adv.Audio.Track3="Piste 3"
Basic.Settings.Output.Adv.Audio.Track4="Piste 4"
+Basic.Settings.Output.Adv.Audio.Track5="Piste 5"
+Basic.Settings.Output.Adv.Audio.Track6="Piste 6"
Basic.Settings.Output.Adv.Recording="Enregistrement"
Basic.Settings.Output.Adv.Recording.Type="Type "
@@ -418,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Paramètres de l'encodeur vid
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Encodeur audio"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Paramètres de l'encodeur audio (le cas échéant)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Paramètres du muxer (le cas échéant)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Intervalle d'images clés (en images)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Afficher tous les codecs (même si potentiellement incompatibles)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -471,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="Espace de couleur YUV"
Basic.Settings.Advanced.Video.ColorRange="Gamme de couleurs YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Partielle"
Basic.Settings.Advanced.Video.ColorRange.Full="Complète"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Dispositif de surveillance audio"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Par défaut"
Basic.Settings.Advanced.StreamDelay="Retard du stream"
Basic.Settings.Advanced.StreamDelay.Duration="Durée (en secondes)"
Basic.Settings.Advanced.StreamDelay.Preserve="Préserver le point de coupure (augmente le retard) lors d'une reconnexion"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Utilisation estimée de la mémoire : %1 Mo"
Basic.Settings.Advanced.Network="Carte réseau (adresse IP source du flux)"
Basic.Settings.Advanced.Network.BindToIP="Lier à :"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Activer le nouveau code réseau"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Mode faible latence"
Basic.AdvAudio="Propriétés audio avancées"
Basic.AdvAudio.Name="Nom"
@@ -484,15 +553,15 @@ Basic.AdvAudio.Volume="Volume (%)"
Basic.AdvAudio.Mono="Passer en mono"
Basic.AdvAudio.Panning="Panoramique polyphonique"
Basic.AdvAudio.SyncOffset="Décalage de la synchronisation (ms)"
+Basic.AdvAudio.Monitoring="Surveillance audio"
+Basic.AdvAudio.Monitoring.None="Désactivé"
+Basic.AdvAudio.Monitoring.MonitorOnly="Surveillance uniquement (couper la sortie)"
+Basic.AdvAudio.Monitoring.Both="Surveillance et sortie"
Basic.AdvAudio.AudioTracks="Pistes"
Basic.Settings.Hotkeys="Raccourcis clavier"
Basic.Settings.Hotkeys.Pair="Les combinaisons de touches partagées avec '%1' agissent comme déclancheur"
-Basic.Hotkeys.StartStreaming="Commencer le streaming"
-Basic.Hotkeys.StopStreaming="Arrêter le streaming"
-Basic.Hotkeys.StartRecording="Démarrer l'enregistrement"
-Basic.Hotkeys.StopRecording="Arrêter l'enregistrement"
Basic.Hotkeys.SelectScene="Passer à la scène"
Basic.SystemTray.Show="Restaurer"
@@ -546,4 +615,5 @@ SceneItemHide="Cacher '%1'"
OutputWarnings.NoTracksSelected="Vous devez sélectionner au moins une piste"
OutputWarnings.MultiTrackRecording="Attention : Certains formats (comme FLV) ne supportent pas les pistes multiples pour un même enregistrement"
+OutputWarnings.MP4Recording="Avertissement: Les enregistrements sauvegardés sur MP4 seront irrécupérables si le fichier ne peut pas être finalisé (par exemple, à cause des BSOD, des pertes de puissance, etc.). Si vous voulez enregistrer plusieurs pistes audio, pensez à utiliser MKV et remux l'enregistrement au mp4 après qu'il est terminé (File-> Remux Recordings)"
diff --git a/UI/data/locale/gl-ES.ini b/UI/data/locale/gl-ES.ini
index eb8b1ee..4ba0744 100644
--- a/UI/data/locale/gl-ES.ini
+++ b/UI/data/locale/gl-ES.ini
@@ -47,6 +47,7 @@ Top="Arriba"
Bottom="Abaixo"
+
Basic.AddTransition="Engadir transición configurable"
Basic.RemoveTransition="Eliminar transición configurable"
Basic.TransitionProperties="Propiedades da transición"
@@ -75,6 +76,7 @@ ConfirmExit.Title="Saír de OBS?"
ConfirmRemove.Title="Confirmar a eliminación"
ConfirmRemove.Text="Tes a certeza de querer eliminar '$1'?"
+
Output.ConnectFail.Title="Erro ao se conectar"
Output.ConnectFail.BadPath="Camiño ou URL de conexión non válidos. Por favor, comproba a configuración para confirmar de que son correctos."
Output.ConnectFail.ConnectFailed="Erro ao conectar co servidor"
@@ -126,6 +128,7 @@ Basic.Main.PreviewConextMenu.Enable="Habilitar vista previa"
+
Basic.Main.AddSceneDlg.Title="Engadir escena"
Basic.Main.AddSceneDlg.Text="Por favor, insire un nome para a escena"
@@ -362,10 +365,6 @@ Basic.AdvAudio.SyncOffset="Sincronización Offset (ms)"
Basic.AdvAudio.AudioTracks="Pistas"
-Basic.Hotkeys.StartStreaming="Iniciar retransmisión"
-Basic.Hotkeys.StopStreaming="Deter retransmisión"
-Basic.Hotkeys.StartRecording="Iniciar gravación"
-Basic.Hotkeys.StopRecording="Deter gravación"
diff --git a/UI/data/locale/he-IL.ini b/UI/data/locale/he-IL.ini
index cbeab9b..c4470c9 100644
--- a/UI/data/locale/he-IL.ini
+++ b/UI/data/locale/he-IL.ini
@@ -49,6 +49,7 @@ Right="ימין"
Top="עליון"
Bottom="תחתון"
+
QuickTransitions.SwapScenes="החלף סצינות תצוגה מקדימה/פלט לאחר המעבר"
QuickTransitions.SwapScenesTT="החלף הסצינות של התצוגה המקדימה ושל הפלט לאחר המעבר (באם הסצינה המקורית של הפלט עדיין קיימת). \n פעולה זו לא תבטל כל שינוי שייתכן ובוצע לסצינה המקורית של הפלט."
QuickTransitions.DuplicateScene="הכפל סצינה"
@@ -89,6 +90,7 @@ ConfirmRemove.Title="אשר הסרה"
ConfirmRemove.Text="האם אתה בטוח שברצונך להסיר את '$1'?"
ConfirmRemove.TextMultiple="האם אתה בטוח שברצונך להסיר %1 פריטים?"
+
Output.ConnectFail.Title="ההתחברות נכשלה"
Output.ConnectFail.BadPath="URL לא חוקי של נתיב או חיבור. נא בדוק את ההגדרות שלך כדי לוודא כי הם נכונים."
Output.ConnectFail.ConnectFailed="ההתחברות לשרת נכשלה"
@@ -163,6 +165,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="שדה עליון ראשון"
Deinterlacing.BottomFieldFirst="שדה תחתון ראשון"
+
Basic.Main.AddSceneDlg.Title="הוסף סצנה"
Basic.Main.AddSceneDlg.Text="אנא הזן את השם של הסצנה"
@@ -483,10 +486,6 @@ Basic.AdvAudio.AudioTracks="ערוצים"
Basic.Settings.Hotkeys="מקשי קיצור"
Basic.Settings.Hotkeys.Pair="צירופי מקשים משותים עם '%1' משמשים כמחליפים"
-Basic.Hotkeys.StartStreaming="התחל הזרמת נתונים"
-Basic.Hotkeys.StopStreaming="עצור הזרמת נתונים"
-Basic.Hotkeys.StartRecording="התחל הקלטה"
-Basic.Hotkeys.StopRecording="עצור הקלטה"
Basic.Hotkeys.SelectScene="עבור לסצנה"
Basic.SystemTray.Show="הצג"
diff --git a/UI/data/locale/hr-HR.ini b/UI/data/locale/hr-HR.ini
index 497e1a9..8fb1343 100644
--- a/UI/data/locale/hr-HR.ini
+++ b/UI/data/locale/hr-HR.ini
@@ -48,6 +48,12 @@ Left="Sleva"
Right="Zdesna"
Top="Odozgo"
Bottom="Odozdo"
+Reset="Poništi"
+Hours="Sati"
+Minutes="Minuta"
+Seconds="Sekundi"
+Deprecated="Prevaziđeno"
+
QuickTransitions.SwapScenes="Zameni scene pregleda/izlaza nakon prelaza"
QuickTransitions.SwapScenesTT="Zamenjuje scene pregleda i izlaza nakon prelaza (ako originalna scena izlaza još uvek postoji).\nOvo neće poništiti promene koje su načinjene nad originalnom scenom izlaza."
@@ -89,6 +95,7 @@ ConfirmRemove.Title="Potvrdi izbacivanje"
ConfirmRemove.Text="Da li ste sigurni da želite izbaciti '$1'?"
ConfirmRemove.TextMultiple="Da li ste sigurni da želite izbaciti %1 stavke?"
+
Output.ConnectFail.Title="Neuspešno povezivanje"
Output.ConnectFail.BadPath="Neispravna putanja ili URL konekcije. Molim proverite vaša podešavanja da potvrdite njihovu ispravnost."
Output.ConnectFail.ConnectFailed="Neuspešno povezivanje na server"
@@ -163,6 +170,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Prvo gornje polje"
Deinterlacing.BottomFieldFirst="Prvo donje polje"
+
Basic.Main.AddSceneDlg.Title="Dodaj scenu"
Basic.Main.AddSceneDlg.Text="Molim unesite ime scene"
@@ -281,6 +289,10 @@ Basic.MainMenu.Edit.Redo="U&radi ponovo"
Basic.MainMenu.Edit.UndoAction="Vrati $1 (&U)"
Basic.MainMenu.Edit.RedoAction="U&radi ponovo $1"
Basic.MainMenu.Edit.LockPreview="Zak&ljučaj prikaz"
+Basic.MainMenu.Edit.Scale="Pregled &skaliranja"
+Basic.MainMenu.Edit.Scale.Window="Skaliraj na veličinu prozora"
+Basic.MainMenu.Edit.Scale.Canvas="Platno (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Izlaz (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformiši"
Basic.MainMenu.Edit.Transform.EditTransform="Izm&eni transformaciju..."
Basic.MainMenu.Edit.Transform.ResetTransform="Poništi t&ransformaciju"
@@ -337,7 +349,6 @@ Basic.Settings.General.SourceSnapping="Privlačenje izvora ka drugim izvorima"
Basic.Settings.General.SnapDistance="Osetljivost privlačenja"
Basic.Settings.General.RecordWhenStreaming="Automatsko snimanje pri emitovanju"
Basic.Settings.General.KeepRecordingWhenStreamStops="Nastavi snimati kada se emitovanje zaustavi"
-Basic.Settings.General.SysTrayEnabled="Omogući ikonicu u sistemskom panelu"
Basic.Settings.General.SysTrayWhenStarted="Pri pokretanju minimiziraj na ikonicu u sistemskom panelu"
Basic.Settings.Stream="Strim"
@@ -368,6 +379,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Upozorenje za kvalitet bez gub
Basic.Settings.Output.Simple.Warn.MultipleQSV="Upozorenje: Ne možete koristi više odvojenih QSV enkodera kada emitujete i snimate u isto vreme. Ako želite da emitujete i snimate u isto vreme, molim promenite ili enkoder snimanja ili enkoder emitovanja."
Basic.Settings.Output.Simple.Encoder.Software="Softverski (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Mašinski (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Mašinski (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Mašinski (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Softverski (x264 niska upotreba procesora, povećava veličinu datoteke)"
Basic.Settings.Output.VideoBitrate="Protok videa"
@@ -487,10 +499,6 @@ Basic.AdvAudio.AudioTracks="Izvori"
Basic.Settings.Hotkeys="Prečice"
Basic.Settings.Hotkeys.Pair="Kombinacije tastera deljene sa '%1' se ponašaju kao prekidači"
-Basic.Hotkeys.StartStreaming="Započni strimovanje"
-Basic.Hotkeys.StopStreaming="Zaustavi strimovanje"
-Basic.Hotkeys.StartRecording="Počni snimanje"
-Basic.Hotkeys.StopRecording="Zaustavi snimanje"
Basic.Hotkeys.SelectScene="Prebaci na scenu"
Basic.SystemTray.Show="Prikaži"
diff --git a/UI/data/locale/hu-HU.ini b/UI/data/locale/hu-HU.ini
index f83119b..e5a74be 100644
--- a/UI/data/locale/hu-HU.ini
+++ b/UI/data/locale/hu-HU.ini
@@ -49,6 +49,26 @@ Right="Jobb"
Top="Felső"
Bottom="Alsó"
Reset="Újraindít"
+Hours="Óra"
+Minutes="Perc"
+Seconds="Másodperc"
+Deprecated="Elavult"
+ReplayBuffer="Visszajátszás puffer"
+Import="Importálás"
+Export="Exportálás"
+
+Updater.Title="Új frissítés elérhető"
+Updater.Text="Új frissítés elérhető:"
+Updater.UpdateNow="Frissítés most"
+Updater.RemindMeLater="Emlékeztessen később"
+Updater.Skip="Verzió átugrása"
+Updater.Running.Title="A program jelenleg aktív"
+Updater.Running.Text="Valamely kimenet jelenleg aktív, állítsa le az aktív kimenetet, mielőtt frissíteni próbál"
+Updater.NoUpdatesAvailable.Title="Nincs elérhető frissítés"
+Updater.NoUpdatesAvailable.Text="Jelenleg nincs elérhető frissítés"
+Updater.FailedToLaunch="Frissítő alkalmazás indítása sikertelen"
+Updater.GameCaptureActive.Title="Játék felvétel aktív"
+Updater.GameCaptureActive.Text="Játékfelvétel hook könyvtár jelenleg használatban. Zárjon be minden játékot/programot, amelyet felvesz (vagy indítsa újra a számítógépét) és próbálkozzon újra."
QuickTransitions.SwapScenes="Előnézeti/Kimeneti Jelenetek cseréje átmenet után"
QuickTransitions.SwapScenesTT="Az előnézet és a kimeneti jelenet cseréje átmenet után (ha a kimenet eredeti jelenete még létezik).\nEz nincs kihatással a kimenet eredeti jelenetére."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Eltávolítás megerősítése"
ConfirmRemove.Text="\"$1\" eltávolítására készül, biztos benne?"
ConfirmRemove.TextMultiple="\"%1\" elem eltávolítására készül, biztos benne?"
+Output.StartStreamFailed="Stream indítása sikertelen"
+Output.StartRecordingFailed="Felvétel indítása sikertelen"
+Output.StartReplayFailed="Visszajátszás puffer indítása sikertelen"
+Output.StartFailedGeneric="Kimenet indítása sikertelen. Kérem ellenőrizze az eseménynaplóban a részleteket.\n\nMegjegyzés: NVENC vagy AMD kódoló használata esetén, győződjön meg róla, hogy az illesztőprogramok naprakészek!"
+
Output.ConnectFail.Title="Csatlakozás sikertelen"
Output.ConnectFail.BadPath="Érvénytelen elérési út vagy kapcsolati URL cím. Kérem, ellenőrizze a beállításokat és győződjön meg az érvényességükről."
Output.ConnectFail.ConnectFailed="Nem sikerült kapcsolódni a szerverhez"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Nincs elég szabad lemezterület"
Output.RecordNoSpace.Msg="Nincs elegendő lemezterület a felvétel folytatásához."
Output.RecordError.Title="Felvételi hiba"
Output.RecordError.Msg="Ismeretlen hiba lépett fel a felvétel során."
+Output.ReplayBuffer.NoHotkey.Title="Nincs gyorsbillentyű beállítva!"
+Output.ReplayBuffer.NoHotkey.Msg="Nincs mentés gyorsbillentyű a visszajátszási pufferhez. Kérem állítson be egy \"Mentés\" gyorsbillentyűt a visszajátszások felvételeinek mentésére."
Output.BadPath.Title="A fájl elérési útja hibás"
Output.BadPath.Text="A beállított elérési útvonal érvénytelen. Kérem ellenőrizze a beállításait és győződjön meg arról, hogy a fájl elérési útja érvényes."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Felső mező először"
Deinterlacing.BottomFieldFirst="Alsó mező először"
+VolControl.SliderUnmuted="Hangerő csúszka a '%1'-hez: %2"
+VolControl.SliderMuted="Hangerő csúszka '%1'-hez: %2 (jelenleg némítva)"
+VolControl.Mute="Némítás '%1'"
+VolControl.Properties="Tulajdonságok a '%1'-hez"
+
Basic.Main.AddSceneDlg.Title="Jelenet hozzáadása"
Basic.Main.AddSceneDlg.Text="Kérem adja meg a jelenet nevét"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Jelenetek"
Basic.Main.Sources="Források"
Basic.Main.Connecting="Kapcsolódás..."
Basic.Main.StartRecording="Felvétel indítása"
+Basic.Main.StartReplayBuffer="Visszajátszás puffer indítása"
Basic.Main.StartStreaming="Stream indítása"
Basic.Main.StopRecording="Felvétel leállítása"
Basic.Main.StoppingRecording="Felvétel leállítása..."
+Basic.Main.StopReplayBuffer="Visszajátszás puffer megállítása"
+Basic.Main.StoppingReplayBuffer="Visszajátszás puffer leáll..."
Basic.Main.StopStreaming="Stream leállítása"
Basic.Main.StoppingStreaming="Stream leállítása..."
Basic.Main.ForceStopStreaming="Stream leállítása (Késleltetés elvetése)"
@@ -269,7 +304,7 @@ Basic.MainMenu.File="&Fájl"
Basic.MainMenu.File.Export="&Exportálás"
Basic.MainMenu.File.Import="&Importálás"
Basic.MainMenu.File.ShowRecordings="&Felvételek megjelenítése"
-Basic.MainMenu.File.Remux="Re&mux felvételek"
+Basic.MainMenu.File.Remux="Felvételek re&muxolása"
Basic.MainMenu.File.Settings="&Beállítások"
Basic.MainMenu.File.ShowSettingsFolder="Beállítási mappa megjelenítése"
Basic.MainMenu.File.ShowProfileFolder="Profilmappa megjelenítése"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Ismét"
Basic.MainMenu.Edit.UndoAction="&Visszavonás $1"
Basic.MainMenu.Edit.RedoAction="&Ismét $1"
Basic.MainMenu.Edit.LockPreview="&Előnézet zárolás"
+Basic.MainMenu.Edit.Scale="Előnézet &méretezés"
+Basic.MainMenu.Edit.Scale.Window="Ablakhoz igazítás"
+Basic.MainMenu.Edit.Scale.Canvas="Vászon (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Kimenet (%1x%2)"
Basic.MainMenu.Edit.Transform="&Alakítás"
Basic.MainMenu.Edit.Transform.EditTransform="&Alakítás átszerkesztése..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Alakítás másolása"
+Basic.MainMenu.Edit.Transform.PasteTransform="Átalakítás beillesztése"
Basic.MainMenu.Edit.Transform.ResetTransform="&Alakítás visszaállítása"
Basic.MainMenu.Edit.Transform.Rotate90CW="Forgatás 90 fokkal balra"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Forgatás 90 fokkal jobbra"
@@ -308,16 +349,22 @@ Basic.MainMenu.View.StatusBar="&Állapotsor"
Basic.MainMenu.SceneCollection="&Jelenet gyűjtemény"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Profil importálása"
+Basic.MainMenu.Profile.Export="Profil exportálása"
+Basic.MainMenu.SceneCollection.Import="Jelenet gyűjtemény importálása"
+Basic.MainMenu.SceneCollection.Export="Jelenet gyűjtemény exportálása"
+Basic.MainMenu.Profile.Exists="A profil már létezik"
+Basic.MainMenu.SceneCollection.Exists="A jelenet gyűjtemény már létezik"
-Basic.MainMenu.Tools="&Eszközők"
+Basic.MainMenu.Tools="&Eszközök"
Basic.MainMenu.Help="&Segítség"
-Basic.MainMenu.Help.Website="Weboldal meglátogatása"
+Basic.MainMenu.Help.Website="Weboldal megtekintése"
Basic.MainMenu.Help.Logs="&Naplófájlok"
Basic.MainMenu.Help.Logs.ShowLogs="&Naplófájlok megjelenítése"
Basic.MainMenu.Help.Logs.UploadCurrentLog="&Aktuális Naplófájl feltöltése"
Basic.MainMenu.Help.Logs.UploadLastLog="&Utolsó Naplófájl feltöltése"
-Basic.MainMenu.Help.Logs.ViewCurrentLog="&Jelenlegi napló megtekintése"
+Basic.MainMenu.Help.Logs.ViewCurrentLog="&Jelenlegi Naplófájl megtekintése"
Basic.MainMenu.Help.CheckForUpdates="Frissítések ellenőrzése"
Basic.Settings.ProgramRestart="A beállítások érvénybe lépéséhez a program újraindítása szükséges."
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Nem mentette a módosításokat. Menti a változtatások
Basic.Settings.General="Általános"
Basic.Settings.General.Theme="Téma"
Basic.Settings.General.Language="Nyelv"
+Basic.Settings.General.EnableAutoUpdates="Indításkor a frissítések automatikus ellenőrzése"
Basic.Settings.General.WarnBeforeStartingStream="Megerősítő párbeszédpanel megjelenítése stream indításakor"
Basic.Settings.General.WarnBeforeStoppingStream="Megerősítő párbeszédpanel megjelenítése stream leállításakor"
+Basic.Settings.General.Projectors="Projektorok"
Basic.Settings.General.HideProjectorCursor="Projektor nézetben a kurzor elrejtése"
Basic.Settings.General.ProjectorAlwaysOnTop="Projektorok mindig legfelül"
Basic.Settings.General.Snapping="Forrás pozicionálásának igazítása"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Források igazítása más forrásokhoz"
Basic.Settings.General.SnapDistance="Igazítás érzékenysége"
Basic.Settings.General.RecordWhenStreaming="Automatikus felvétel stream esetén"
Basic.Settings.General.KeepRecordingWhenStreamStops="Felvétel folytatása a stream leállása esetén"
-Basic.Settings.General.SysTrayEnabled="Tálca ikon elhelyezése"
+Basic.Settings.General.ReplayBufferWhileStreaming="Automatikusan induljon a visszajátszás puffer stream megkezdésekor"
+Basic.Settings.General.KeepReplayBufferStreamStops="Visszajátszás puffer aktívan tartása stream leállása esetén"
+Basic.Settings.General.SysTray="Tálca"
Basic.Settings.General.SysTrayWhenStarted="Indításkor ikonként a tálcán"
+Basic.Settings.General.SystemTrayHideMinimize="Mindig a rendszertálcára minimalizálás tálca helyett"
+Basic.Settings.General.SaveProjectors="Projektorok mentése kilépéskor"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Stream típusa"
@@ -349,19 +402,27 @@ Basic.Settings.Output.Format="Felvétel formátuma"
Basic.Settings.Output.Encoder="Kódoló"
Basic.Settings.Output.SelectDirectory="Felvételi könyvtár kiválasztása"
Basic.Settings.Output.SelectFile="Felvétel fájljának kiválasztása"
-Basic.Settings.Output.EnforceBitrate="Stream kiszolgáló bitráta korlátainak kényszerítése"
+Basic.Settings.Output.EnforceBitrate="Stream kiszolgáló bitsebesség korlátainak kényszerítése"
Basic.Settings.Output.Mode="Kimeneti mód"
Basic.Settings.Output.Mode.Simple="Egyszerű"
Basic.Settings.Output.Mode.Adv="Haladó"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg kimenet"
+Basic.Settings.Output.UseReplayBuffer="Visszajátszás puffer engedélyezése"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximális visszajátszási idő (Másodperc)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximális memória (Megabájt)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Becsült memóriaigény: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nem lehet megbecsülni a memóriaigényt. Kérem állítson be egy maximális memória limitet."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Megjegyzés: Bizonyosodjon meg róla, hogy beállított egy billentyűparancsot az újrajátszás pufferre a gyorsbillentyű szekcióban)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Visszajátszási puffer fájlév előtag"
+Basic.Settings.Output.ReplayBuffer.Suffix="Utótag"
Basic.Settings.Output.Simple.SavePath="Felvétel helye"
Basic.Settings.Output.Simple.RecordingQuality="Felvétel minősége"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Ugyanaz, mint a stream"
Basic.Settings.Output.Simple.RecordingQuality.Small="Jó minőség, közepes fájlméret"
Basic.Settings.Output.Simple.RecordingQuality.HQ="Megkülönböztethetetlen minőség, nagy fájlméret"
Basic.Settings.Output.Simple.RecordingQuality.Lossless="Veszteségmentes minőség, hatalmas fájlméret"
-Basic.Settings.Output.Simple.Warn.VideoBitrate="Figyelem: Az adás videó bitrátája %1 értéken áll, ami a kiválasztott kiszolgáló felső határértéke. Amennyiben túl kívánja lépni a megadott %1 értéket, úgy engedélyezze a haladó kódolási opciókat és törölje a \"stream kiszolgáló bitráta korlátainak kényszerítése\" opciót."
-Basic.Settings.Output.Simple.Warn.AudioBitrate="Figyelem: Az adás audio bitrátája %1 értéken áll, ami a kiválasztott kiszolgáló felső határértéke. Amennyiben túl kívánja lépni a megadott %1 értéket, úgy engedélyezze a haladó kódolási opciókat és törölje a \"stream kiszolgáló bitráta korlátainak kényszerítése\" opciót."
+Basic.Settings.Output.Simple.Warn.VideoBitrate="Figyelem: Az adás videó bitsebessége %1 értéken áll, ami a kiválasztott kiszolgáló felső határértéke. Amennyiben túl kívánja lépni a megadott %1 értéket, úgy engedélyezze a haladó kódolási opciókat és törölje a \"stream kiszolgáló bitsebesség korlátainak kényszerítése\" opciót."
+Basic.Settings.Output.Simple.Warn.AudioBitrate="Figyelem: Az adás audio bitsebessége %1 értéken áll, ami a kiválasztott kiszolgáló felső határértéke. Amennyiben túl kívánja lépni a megadott %1 értéket, úgy engedélyezze a haladó kódolási opciókat és törölje a \"stream kiszolgáló bitsebesség korlátainak kényszerítése\" opciót."
Basic.Settings.Output.Simple.Warn.Encoder="Figyelem: A streamtől eltérő minőséggel történő rögzítés, további CPU erőforrásokat igényel, ha egyidejűleg használja mindkettőt."
Basic.Settings.Output.Simple.Warn.Lossless="Figyelem: A veszteségmentes minőséggel történő felvétel hatalmas fájlméretet generál. Ezzel a minőséggel percenként akár 7 gigabájt adatot is generálhat nagy felbontáson és képkockasebességen. Ez az eljárás nem ajánlott hosszú felvételekhez, kivéve ha hatalmas lemezterület áll rendelkezésre."
Basic.Settings.Output.Simple.Warn.Lossless.Msg="Biztos benne, hogy veszteségmentes minőséget kíván használni?"
@@ -372,8 +433,8 @@ Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardver (QSV)"
Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardver (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardver (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Szoftveres (x264 alacsony CPU használati készlet, növekvő fájlméret)"
-Basic.Settings.Output.VideoBitrate="Videó bitráta"
-Basic.Settings.Output.AudioBitrate="Audio bitráta"
+Basic.Settings.Output.VideoBitrate="Videó bitsebesség"
+Basic.Settings.Output.AudioBitrate="Audio bitsebesség"
Basic.Settings.Output.Reconnect="Automatikus újracsatlakozás"
Basic.Settings.Output.RetryDelay="Újrapróbálkozás késleltetése (másodperc)"
Basic.Settings.Output.MaxRetries="Újrapróbálkozások maximális száma"
@@ -391,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Sáv 1"
Basic.Settings.Output.Adv.Audio.Track2="Sáv 2"
Basic.Settings.Output.Adv.Audio.Track3="Sáv 3"
Basic.Settings.Output.Adv.Audio.Track4="Sáv 4"
+Basic.Settings.Output.Adv.Audio.Track5="Sáv 5"
+Basic.Settings.Output.Adv.Audio.Track6="Sáv 6"
Basic.Settings.Output.Adv.Recording="Rögzítés"
Basic.Settings.Output.Adv.Recording.Type="Típus"
@@ -418,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Videó kódoló beállításo
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio kódoló"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audio kódoló beállítások (ha van)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer beállítások (ha van)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Kulcsképkocka időköz (képkockák)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Minden kodek mutatása (még ha inkompatibilisek is)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -471,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV színtér"
Basic.Settings.Advanced.Video.ColorRange="YUV színtartomány"
Basic.Settings.Advanced.Video.ColorRange.Partial="Részleges"
Basic.Settings.Advanced.Video.ColorRange.Full="Teljes"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Hangfigyelő eszköz"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Alapértelmezett"
Basic.Settings.Advanced.StreamDelay="Stream késleltetés"
Basic.Settings.Advanced.StreamDelay.Duration="Időtartam (másodperc)"
Basic.Settings.Advanced.StreamDelay.Preserve="Töréspont megőrzése (Késleltetés növeléssel) újrakapcsolódás esetén"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Becsült memóriahasználat: %1 MB"
Basic.Settings.Advanced.Network="Hálózat"
Basic.Settings.Advanced.Network.BindToIP="IP-hez rendelés"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Új hálózatkezelő kód engedélyezése"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Alacsony késleltetésű mód"
Basic.AdvAudio="Speciális hangtulajdonságok"
Basic.AdvAudio.Name="Név"
@@ -484,15 +553,15 @@ Basic.AdvAudio.Volume="Hangerő (%)"
Basic.AdvAudio.Mono="Monora lekeverés"
Basic.AdvAudio.Panning="Keverő"
Basic.AdvAudio.SyncOffset="Szinkron eltolás (ms)"
+Basic.AdvAudio.Monitoring="Hangfigyelés"
+Basic.AdvAudio.Monitoring.None="Figyelés kikapcsolása"
+Basic.AdvAudio.Monitoring.MonitorOnly="Csak figyelés (kimenet némítása)"
+Basic.AdvAudio.Monitoring.Both="Figyelés és kimenet"
Basic.AdvAudio.AudioTracks="Sávok"
Basic.Settings.Hotkeys="Gyorsbillentyűk"
Basic.Settings.Hotkeys.Pair="Azonos billentyűkombináció a '%1' mezővel, ezért kapcsolóként működik"
-Basic.Hotkeys.StartStreaming="Stream indítása"
-Basic.Hotkeys.StopStreaming="Stream leállítása"
-Basic.Hotkeys.StartRecording="Felvétel indítása"
-Basic.Hotkeys.StopRecording="Felvétel leállítása"
Basic.Hotkeys.SelectScene="Jelenethez kapcsolás"
Basic.SystemTray.Show="Mutat"
@@ -546,4 +615,5 @@ SceneItemHide="Elrejti '%1'"
OutputWarnings.NoTracksSelected="Ki kell jelölnie legalább egy sávot!"
OutputWarnings.MultiTrackRecording="Figyelem: Bizonyos formátumok (mint az FLV) nem támogatják a több sávot felvételenként"
+OutputWarnings.MP4Recording="Figyelem: Az MP4-be mentett állományok javíthatatlanok, ha a fájl nem kerül lezárásra (pl: BSOD vagy áramkimaradás esetén, stb.). Ha mindenképpen több hangsávval kíván felvételt készíteni, akkor használja az MKV állományt és remuxolja a felvételt MP4-be, miután elkészült. (Fájl->Felvételek remuxolása)"
diff --git a/UI/data/locale/it-IT.ini b/UI/data/locale/it-IT.ini
index db93731..c35ed2b 100644
--- a/UI/data/locale/it-IT.ini
+++ b/UI/data/locale/it-IT.ini
@@ -20,7 +20,7 @@ Properties="Proprietà"
MoveUp="Sposta su"
MoveDown="Sposta giù"
Settings="Impostazioni"
-Display="Display"
+Display="Schermo"
Name="Nome"
Exit="Esci"
Mixer="Mixer"
@@ -28,31 +28,40 @@ Browse="Sfoglia"
Mono="Mono"
Stereo="Stereo"
DroppedFrames="Fotogrammi persi %1 (%2%)"
-PreviewProjector="Proiettore Schermo intero (Anteprima)"
-SceneProjector="Proiettore Schermo intero (Scena)"
-SourceProjector="Proiettore Schermo intero (Sorgente)"
+PreviewProjector="Proiettore a schermo intero (anteprima)"
+SceneProjector="Proiettore a schermo intero (scena)"
+SourceProjector="Proiettore a schermo intero (sorgente)"
Clear="Svuota"
Revert="Ripristina"
Show="Mostra"
Hide="Nascondi"
-Untitled="Senza Titolo"
+Untitled="Senza titolo"
New="Nuovo"
Duplicate="Duplica"
Enable="Abilita"
-DisableOSXVSync="Disabilita il V-Sync OSX"
-ResetOSXVSyncOnExit="Reimpostare V-Sync OSX in uscita"
-HighResourceUsage="Codifica in sovraccarico! È consigliabile abbassare le impostazioni video o utilizzare un settaggio predefinito di codifica più veloce."
+DisableOSXVSync="Disabilita V-Sync OSX"
+ResetOSXVSyncOnExit="Reimposta V-Sync OSX in uscita"
+HighResourceUsage="Codifica in sovraccarico! È consigliabile abbassare le impostazioni video o utilizzare una preimpostazione predefinita di codifica più veloce."
Transition="Transizione"
QuickTransitions="Transizioni rapide"
Left="Sinistra"
Right="Destra"
Top="Alto"
Bottom="Basso"
+Reset="Ripristina"
+Hours="Ore"
+Minutes="Minuti"
+Seconds="Secondi"
+Deprecated="Deprecato"
+ReplayBuffer="Buffer di replay"
+Import="Importa"
+Export="Esporta"
-QuickTransitions.SwapScenes="Scambia Scena Preview/Uscita dopo la Transizione"
-QuickTransitions.SwapScenesTT="Scambia la scena in uniscita con quella in preview dopo la transizione (ammesso che la scena in uscita originale ci sia ancora).\nQuesto non modificherà eventuali cambiamenti apportati alla scena di uscita originale."
-QuickTransitions.DuplicateScene="Duplica Scena"
-QuickTransitions.DuplicateSceneTT="Quando si modifica la stessa scena, permette di modificare la trasformazione/visibilità di source senza modificare l'output. \nPer modificare le proprietà delle source senza modificare l'output, abilità 'Source duplicate'.\nCambiare questo valore resetterà la scena output attuale (se esite ancora)."
+
+QuickTransitions.SwapScenes="Scambia scene di anteprima/uscita dopo la transizione"
+QuickTransitions.SwapScenesTT="Scambia le scene di uscita con quella in anteprima dopo la transizione (ammesso che la scena in uscita originale ci sia ancora).\nQuesto non modificherà eventuali cambiamenti apportati alla scena di uscita originale."
+QuickTransitions.DuplicateScene="Duplica scena"
+QuickTransitions.DuplicateSceneTT="Quando si modifica la stessa scena, permette di modificare la trasformazione/visibilità delle sorgenti senza modificare l'uscita.\nPer modificare le proprietà delle source senza modificare l'uscita, abilità 'Sorgenti duplicate'.\nCambiare questo valore ripristinerà la scena di uscita attuale (se esiste ancora)."
QuickTransitions.EditProperties="Duplica Risorsa"
QuickTransitions.EditPropertiesTT="Quando si modifica la stessa scena, consente la modifica di risorse senza modificarne l'output. \nQuesto può essere usato solo se 'Scene doppia' è attivo. \nCerte risorse (come media o catture) non lo supportano e devono essere modificate separatamente. \nCambiare questo valore resetterà l'attuale scena di output (se esiste ancora). \n\nAttenzione: Dato che la risorsa verrà duplicata, questo potrebbe richiedere risorse di sistema o video aggiuntive."
QuickTransitions.HotkeyName="Transizioni rapide: %1"
@@ -64,7 +73,7 @@ Basic.SceneTransitions="Transizioni di scena"
Basic.TransitionDuration="Durata"
Basic.TogglePreviewProgramMode="Modalità studio"
-TransitionNameDlg.Text="Per favore inserisci il nome della transizione"
+TransitionNameDlg.Text="Inserisci il nome della transizione"
TransitionNameDlg.Title="Nome transizione"
TitleBar.Profile="Profilo"
@@ -76,19 +85,20 @@ NameExists.Text="Il nome è già in uso."
NoNameEntered.Title="Inserisci un nome valido"
NoNameEntered.Text="Non è possibile utilizzare nomi vuoti."
-ConfirmStart.Title="Inizia diretta?"
+ConfirmStart.Title="Vuoi iniziare la trasmissione?"
ConfirmStart.Text="Sei sicuro di voler iniziare una diretta?"
-ConfirmStop.Title="Interrompere diretta?"
-ConfirmStop.Text="Sei sicuro di voler interrompere questa diretta?"
+ConfirmStop.Title="Vuoi fermare la trasmissione?"
+ConfirmStop.Text="Sei sicuro di voler interrompere questa trasmissione?"
-ConfirmExit.Title="Uscire da OBS?"
+ConfirmExit.Title="Vuoi uscire da OBS?"
ConfirmExit.Text="OBS è attualmente attivo. Tutte le dirette/registrazioni saranno fermate. Sei sicuro di voler uscire?"
ConfirmRemove.Title="Conferma la rimozione"
ConfirmRemove.Text="Sei sicuro di voler rimuovere '$1'?"
ConfirmRemove.TextMultiple="Sei sicuro di volere rimuovere %1 elementi?"
+
Output.ConnectFail.Title="Impossibile connettersi"
Output.ConnectFail.BadPath="Percorso o URL di connessione non valido. Controlla le tue impostazioni per confermare che siano valide."
Output.ConnectFail.ConnectFailed="Connessione al server fallita"
@@ -102,6 +112,8 @@ Output.RecordNoSpace.Title="Spazio su disco insufficiente"
Output.RecordNoSpace.Msg="Non c'è abbastanza spazio su disco per continuazre la registrazione."
Output.RecordError.Title="Errore di registrazione"
Output.RecordError.Msg="Si è verificato un errore non specificato durante la registrazione."
+Output.ReplayBuffer.NoHotkey.Title="Nessuna scorciatoia assegnata!"
+Output.ReplayBuffer.NoHotkey.Msg="Nessuna scorciatoia impostata per salvare il buffer di replay. Impostare la scorciatoia \"Salva\" per poter salvare le registrazioni in replay."
Output.BadPath.Title="Percorso di file invalido"
Output.BadPath.Text="Il percorso configurato per il file di output non è valido. Controlla le tue impostazioni per confermare che un percorso di file valido è stato impostato."
@@ -122,8 +134,8 @@ Remux.Remux="Converti"
Remux.OBSRecording="Registrazione OBS"
Remux.FinishedTitle="Conversione finita"
Remux.Finished="Registrazione convertita"
-Remux.FinishedError="Registrazione convertita, ma il file potrebbe essere incompleta"
-Remux.SelectRecording="Selezionare registrazione OBS …"
+Remux.FinishedError="Registrazione convertita, ma il file potrebbe essere incompleto"
+Remux.SelectRecording="Selezionare registrazione OBS…"
Remux.SelectTarget="Selezionare il file di destinazione…"
Remux.FileExistsTitle="Il file di destinazione esiste"
Remux.FileExists="Il file di destinazione esiste, si desidera sostituirlo?"
@@ -143,7 +155,7 @@ Basic.AuxDevice4="Mic/Aux 4"
Basic.Scene="Scena"
Basic.DisplayCapture="Mostra cattura"
-Basic.Main.PreviewConextMenu.Enable="Abilita Anteprima"
+Basic.Main.PreviewConextMenu.Enable="Abilita anteprima"
ScaleFiltering="Scala di filtraggio"
ScaleFiltering.Point="Punto"
@@ -163,6 +175,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Priorità livello superiore"
Deinterlacing.BottomFieldFirst="Priorità livello inferiore"
+
Basic.Main.AddSceneDlg.Title="Aggiungi scena"
Basic.Main.AddSceneDlg.Text="Inserisci il nome della scena"
@@ -257,9 +270,12 @@ Basic.Main.Scenes="Scene"
Basic.Main.Sources="Origini"
Basic.Main.Connecting="Connessione..."
Basic.Main.StartRecording="Avvia registrazione"
+Basic.Main.StartReplayBuffer="Avvia Buffer di Replay"
Basic.Main.StartStreaming="Avvia trasmissione"
Basic.Main.StopRecording="Ferma registrazione"
Basic.Main.StoppingRecording="Fermando la registrazione..."
+Basic.Main.StopReplayBuffer="Termina Buffer di Replay"
+Basic.Main.StoppingReplayBuffer="Fermando il Buffer di Replay..."
Basic.Main.StopStreaming="Ferma trasmissione"
Basic.Main.StoppingStreaming="Arresto diretta..."
Basic.Main.ForceStopStreaming="Ferma Diretta (annulla ritardo)"
@@ -273,16 +289,22 @@ Basic.MainMenu.File.Settings="&Impostazioni"
Basic.MainMenu.File.ShowSettingsFolder="Visualizza cartella impostazioni"
Basic.MainMenu.File.ShowProfileFolder="Mostra la cartella del profilo"
Basic.MainMenu.AlwaysOnTop="&Sempre in primo piano"
-Basic.MainMenu.File.Exit="Esci (&X)"
+Basic.MainMenu.File.Exit="E&sci"
Basic.MainMenu.Edit="&Modifica"
Basic.MainMenu.Edit.Undo="&Annulla"
Basic.MainMenu.Edit.Redo="&Ripristina"
Basic.MainMenu.Edit.UndoAction="&Ripristina $1"
Basic.MainMenu.Edit.RedoAction="&Ripristina $1"
-Basic.MainMenu.Edit.LockPreview="&Blocca Anteprima"
+Basic.MainMenu.Edit.LockPreview="&Blocca anteprima"
+Basic.MainMenu.Edit.Scale="Anteprima ridimen&sionamento"
+Basic.MainMenu.Edit.Scale.Window="Scala alla finestra"
+Basic.MainMenu.Edit.Scale.Canvas="Tela (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Uscita (%1x%2)"
Basic.MainMenu.Edit.Transform="&Trasforma"
Basic.MainMenu.Edit.Transform.EditTransform="&Modifica e trasforma..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Copia Trasformazione"
+Basic.MainMenu.Edit.Transform.PasteTransform="Incolla Trasformazione"
Basic.MainMenu.Edit.Transform.ResetTransform="&Reset e trasforma"
Basic.MainMenu.Edit.Transform.Rotate90CW="Ruota di 90 gradi DW"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Ruota di 90 gradi CCW"
@@ -297,7 +319,7 @@ Basic.MainMenu.Edit.Order.MoveUp="Muovi &Sopra"
Basic.MainMenu.Edit.Order.MoveDown="Sposta in &basso"
Basic.MainMenu.Edit.Order.MoveToTop="Sposta in &primo piano"
Basic.MainMenu.Edit.Order.MoveToBottom="Sposta in &fondo"
-Basic.MainMenu.Edit.AdvAudio="Proprietà Audio &Avanzate"
+Basic.MainMenu.Edit.AdvAudio="Proprietà audio &avanzate"
Basic.MainMenu.View="&Visualizza"
Basic.MainMenu.View.Toolbars="&Barre degli strumenti"
@@ -307,9 +329,16 @@ Basic.MainMenu.View.StatusBar="&Barra di stato"
Basic.MainMenu.SceneCollection="&Collezione scene"
Basic.MainMenu.Profile="&Profilo"
+Basic.MainMenu.Profile.Import="Importa profilo"
+Basic.MainMenu.Profile.Export="Esporta profilo"
+Basic.MainMenu.SceneCollection.Import="Importa collezione scene"
+Basic.MainMenu.SceneCollection.Export="Esporta collezione scene"
+Basic.MainMenu.Profile.Exists="Il profilo esiste già"
+Basic.MainMenu.SceneCollection.Exists="La collezione di scene già esiste"
+Basic.MainMenu.Tools="&Strumenti"
-Basic.MainMenu.Help="Aiuto (&H)"
+Basic.MainMenu.Help="&Aiuto"
Basic.MainMenu.Help.Website="Visita il sito"
Basic.MainMenu.Help.Logs="File di &log"
Basic.MainMenu.Help.Logs.ShowLogs="&Visualizza i file di Log"
@@ -328,6 +357,7 @@ Basic.Settings.General.Language="Lingua"
Basic.Settings.General.WarnBeforeStartingStream="Chiedi conferma quando si avvia una diretta"
Basic.Settings.General.WarnBeforeStoppingStream="Chiedi conferma quando si termina una diretta"
Basic.Settings.General.HideProjectorCursor="Nascondi cursore sopra proiettori"
+Basic.Settings.General.ProjectorAlwaysOnTop="Rendono i proiettori sempre in primo piano"
Basic.Settings.General.Snapping="Allineamento Snapping Source"
Basic.Settings.General.ScreenSnapping="Snap source nei bordi dello schermo"
Basic.Settings.General.CenterSnapping="Snap source al centro orizzontale e verticale"
@@ -335,6 +365,8 @@ Basic.Settings.General.SourceSnapping="Snap sources ad altre sources"
Basic.Settings.General.SnapDistance="Sensibilità Snap"
Basic.Settings.General.RecordWhenStreaming="Registra automaticamente quando si è in diretta"
Basic.Settings.General.KeepRecordingWhenStreamStops="Continua a registrare quando la diretta s'interrompe"
+Basic.Settings.General.SysTrayWhenStarted="Minimizza all'area di notifica all'avvio"
+Basic.Settings.General.SystemTrayHideMinimize="Minimizza sempre nel vassoio di sistema invece che nella barra delle applicazioni"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Tipo di stream"
@@ -349,6 +381,14 @@ Basic.Settings.Output.Mode="Modalità di output"
Basic.Settings.Output.Mode.Simple="Semplice"
Basic.Settings.Output.Mode.Adv="Avanzate"
Basic.Settings.Output.Mode.FFmpeg="Uscita FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Abilita il Buffer di Replay"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Tempo massimo di Replay (Secondi)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Memoria Massima (Megabytes)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Uso della memoria stimato: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Impossibile stimare la memoria utilizzata. Impostare un limite massimo di memoria."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Nota: Assicurati di aver impostato una hotkey per il Buffer di Replay nella sezione delle hotkeys)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Prefisso del file per i Buffer di Replay"
+Basic.Settings.Output.ReplayBuffer.Suffix="Suffisso"
Basic.Settings.Output.Simple.SavePath="Percorso registrazione"
Basic.Settings.Output.Simple.RecordingQuality="Qualità della registrazione"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Stesso della diretta"
@@ -364,6 +404,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Avviso sulla qualità lossless
Basic.Settings.Output.Simple.Warn.MultipleQSV="Attenzione: Non è possibile usare più encoder QSV quando si è in diretta e si registra allo stesso tempo. Se vuoi andare in diretta e registrare allo stesso tempo, cambia l'encoder per la registrazione o l'encoder per la diretta."
Basic.Settings.Output.Simple.Encoder.Software="Software (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 Preset con basso utilizzo della CPU, aumenta le dimensioni del file)"
Basic.Settings.Output.VideoBitrate="Bitrate video"
@@ -385,13 +426,15 @@ Basic.Settings.Output.Adv.Audio.Track1="Traccia 1"
Basic.Settings.Output.Adv.Audio.Track2="Traccia 2"
Basic.Settings.Output.Adv.Audio.Track3="Traccia 3"
Basic.Settings.Output.Adv.Audio.Track4="Traccia 4"
+Basic.Settings.Output.Adv.Audio.Track5="Traccia 5"
+Basic.Settings.Output.Adv.Audio.Track6="Traccia 6"
Basic.Settings.Output.Adv.Recording="Registrazione"
Basic.Settings.Output.Adv.Recording.Type="Tipo"
Basic.Settings.Output.Adv.Recording.Type.Standard="Standard"
Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Output personalizzato (FFmpeg)"
Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Utilizzare il codificatore del flusso)"
-Basic.Settings.Output.Adv.Recording.Filename="Formattazione del nome del file"
+Basic.Settings.Output.Adv.Recording.Filename="Formattazione nome del file"
Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Sovrascrivi il file se già esistente"
Basic.Settings.Output.Adv.FFmpeg.Type="Tipo di Output FFmpeg"
Basic.Settings.Output.Adv.FFmpeg.Type.URL="Output in URL"
@@ -465,6 +508,8 @@ Basic.Settings.Advanced.Video.ColorSpace="Spazio colore YUV"
Basic.Settings.Advanced.Video.ColorRange="Gamma di colore YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Parziale"
Basic.Settings.Advanced.Video.ColorRange.Full="Intero"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Dispositivo monitor audio"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Predefinito"
Basic.Settings.Advanced.StreamDelay="Ritardo Diretta"
Basic.Settings.Advanced.StreamDelay.Duration="Durata (secondi)"
Basic.Settings.Advanced.StreamDelay.Preserve="Preserva il punto di taglio (aumenta ritardo) durante la riconnessione"
@@ -472,24 +517,27 @@ Basic.Settings.Advanced.StreamDelay.MemoryUsage="Utilizzo di memoria stimato: %1
Basic.Settings.Advanced.Network="Rete"
Basic.Settings.Advanced.Network.BindToIP="Associa a IP"
-Basic.AdvAudio="Proprietà Audio Avanzate"
+Basic.AdvAudio="Proprietà audio avanzate"
Basic.AdvAudio.Name="Nome"
Basic.AdvAudio.Volume="Volume (%)"
Basic.AdvAudio.Mono="Downmix to Mono"
Basic.AdvAudio.Panning="Panning"
Basic.AdvAudio.SyncOffset="Sync Offset (ms)"
+Basic.AdvAudio.Monitoring="Monitor audio"
+Basic.AdvAudio.Monitoring.None="Monitor spento"
+Basic.AdvAudio.Monitoring.MonitorOnly="Solo monitor (uscita silenziata)"
+Basic.AdvAudio.Monitoring.Both="Monitor e uscita"
Basic.AdvAudio.AudioTracks="Tracce"
Basic.Settings.Hotkeys="Tasti di scelta rapida"
Basic.Settings.Hotkeys.Pair="La combinazione di chiavi condivisa con '%1' funziona da commutatore"
-Basic.Hotkeys.StartStreaming="Inizia diretta"
-Basic.Hotkeys.StopStreaming="Termina diretta"
-Basic.Hotkeys.StartRecording="Inizia registrazione"
-Basic.Hotkeys.StopRecording="Ferma registrazione"
Basic.Hotkeys.SelectScene="Passa alla scena"
+Basic.SystemTray.Show="Mostra"
+Basic.SystemTray.Hide="Nascondi"
+Basic.SystemTray.Message.Reconnecting="Disconnesso. Riconnessione..."
Hotkeys.Insert="Ins"
Hotkeys.Delete="Canc"
diff --git a/UI/data/locale/ja-JP.ini b/UI/data/locale/ja-JP.ini
index 9fcd29c..4225e00 100644
--- a/UI/data/locale/ja-JP.ini
+++ b/UI/data/locale/ja-JP.ini
@@ -49,6 +49,26 @@ Right="右"
Top="上"
Bottom="下"
Reset="リセット"
+Hours="時間"
+Minutes="分"
+Seconds="秒"
+Deprecated="非推奨"
+ReplayBuffer="リプレイバッファー"
+Import="インポート"
+Export="エクスポート"
+
+Updater.Title="利用可能な更新"
+Updater.Text="利用可能な更新があります:"
+Updater.UpdateNow="今すぐ更新"
+Updater.RemindMeLater="後で通知"
+Updater.Skip="バージョンをスキップする"
+Updater.Running.Title="現在アクティブなプログラム"
+Updater.Running.Text="出力が現在アクティブです。更新を試みる前にアクティブな出力をシャットダウンしてください。"
+Updater.NoUpdatesAvailable.Title="利用可能な更新はありません"
+Updater.NoUpdatesAvailable.Text="現在利用可能な更新はありません"
+Updater.FailedToLaunch="アップデータの起動に失敗しました"
+Updater.GameCaptureActive.Title="ゲームキャプチャがアクティブ"
+Updater.GameCaptureActive.Text="ゲームキャプチャフックライブラリが現在使用中です。キャプチャされているすべてのゲーム/プログラムを閉じて (またはwindowsを再起動して) からもう一度やり直してください。"
QuickTransitions.SwapScenes="トランジション後にプレビュー/出力シーンを入れ替え"
QuickTransitions.SwapScenesTT="(出力のオリジナルシーンがまだ存在する場合)、トランジション後のプレビューと出力シーンを入れ替えます。\nこれは出力のオリジナルシーンに加えられた可能性があるすべての変更を元に戻しません。"
@@ -90,6 +110,11 @@ ConfirmRemove.Title="削除の確認"
ConfirmRemove.Text="'$1' を削除してもよろしいですか?"
ConfirmRemove.TextMultiple="選択した %1 項目を削除してもよろしいですか?"
+Output.StartStreamFailed="配信開始に失敗しました"
+Output.StartRecordingFailed="録画開始に失敗しました"
+Output.StartReplayFailed="リプレイバッファーの開始に失敗しました"
+Output.StartFailedGeneric="出力開始に失敗しました。詳細はログを確認してください。\n\n注: NVENCまたはAMDエンコーダを使用している場合は、ビデオドライバが最新のものであるかを確認してください。"
+
Output.ConnectFail.Title="接続失敗"
Output.ConnectFail.BadPath="パスかURLが無効です。再確認して下さい。"
Output.ConnectFail.ConnectFailed="サーバーへの接続に失敗しました"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="ディスク領域の不足"
Output.RecordNoSpace.Msg="録画を継続する十分なディスク領域がありません。"
Output.RecordError.Title="録画エラー"
Output.RecordError.Msg="録画中に不明なエラーが発生しました。"
+Output.ReplayBuffer.NoHotkey.Title="ホットキーが設定されていません!"
+Output.ReplayBuffer.NoHotkey.Msg="リプレイバッファー保存のホットキー設定がありません。 リプレイ録画保存用に使用する「保存」のホットキーを設定してください。"
Output.BadPath.Title="無効なパス"
Output.BadPath.Text="設定されたファイルの出力パスが無効です。有効なファイルパスが設定されていることを確認してください。"
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="トップフィールドが先"
Deinterlacing.BottomFieldFirst="ボトムフィールドが先"
+VolControl.SliderUnmuted="'%1' の音量スライダー: %2"
+VolControl.SliderMuted="'%1' の音量スライダー: %2 (現在ミュート)"
+VolControl.Mute="'%1' をミュート"
+VolControl.Properties="'%1' のプロパティ"
+
Basic.Main.AddSceneDlg.Title="シーン追加"
Basic.Main.AddSceneDlg.Text="シーンの名前を入力してください"
@@ -258,11 +290,14 @@ Basic.Main.Scenes="シーン"
Basic.Main.Sources="ソース"
Basic.Main.Connecting="接続中..."
Basic.Main.StartRecording="録画開始"
+Basic.Main.StartReplayBuffer="リプレイバッファー開始"
Basic.Main.StartStreaming="配信開始"
Basic.Main.StopRecording="録画終了"
-Basic.Main.StoppingRecording="録画を停止しています..."
+Basic.Main.StoppingRecording="録画停止処理中..."
+Basic.Main.StopReplayBuffer="リプレイバッファー停止"
+Basic.Main.StoppingReplayBuffer="リプレイバッファー停止処理中..."
Basic.Main.StopStreaming="配信終了"
-Basic.Main.StoppingStreaming="配信を停止しています..."
+Basic.Main.StoppingStreaming="配信停止処理中..."
Basic.Main.ForceStopStreaming="配信停止 (遅延破棄)"
Basic.MainMenu.File="ファイル(&F)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="やり直し(&R)"
Basic.MainMenu.Edit.UndoAction="$1 を元に戻す(&U)"
Basic.MainMenu.Edit.RedoAction="$1 をやり直す(&R)"
Basic.MainMenu.Edit.LockPreview="ロックプレビュー(&L)"
+Basic.MainMenu.Edit.Scale="プレビュースケーリング(&S)"
+Basic.MainMenu.Edit.Scale.Window="ウィンドウサイズにスケーリング表示"
+Basic.MainMenu.Edit.Scale.Canvas="基本(キャンバス) (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="出力(スケーリング) (%1x%2)"
Basic.MainMenu.Edit.Transform="変換(&T)"
Basic.MainMenu.Edit.Transform.EditTransform="変換の編集...(&E)"
+Basic.MainMenu.Edit.Transform.CopyTransform="変換をコピー"
+Basic.MainMenu.Edit.Transform.PasteTransform="変換を貼り付け"
Basic.MainMenu.Edit.Transform.ResetTransform="変換をリセット(&R)"
Basic.MainMenu.Edit.Transform.Rotate90CW="時計回りに 90 度回転"
Basic.MainMenu.Edit.Transform.Rotate90CCW="反時計回りに 90 度回転"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="ステータスバー(&S)"
Basic.MainMenu.SceneCollection="シーンコレクション(&S)"
Basic.MainMenu.Profile="プロファイル(&P)"
+Basic.MainMenu.Profile.Import="プロファイルをインポート"
+Basic.MainMenu.Profile.Export="プロファイルをエクスポート"
+Basic.MainMenu.SceneCollection.Import="シーンコレクションをインポート"
+Basic.MainMenu.SceneCollection.Export="シーンコレクションをエクスポート"
+Basic.MainMenu.Profile.Exists="プロファイルは既に存在します"
+Basic.MainMenu.SceneCollection.Exists="シーンコレクションは既に存在します"
Basic.MainMenu.Tools="ツール(&T)"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="保存していない変更があります。変更を
Basic.Settings.General="一般"
Basic.Settings.General.Theme="テーマ"
Basic.Settings.General.Language="言語"
+Basic.Settings.General.EnableAutoUpdates="起動時に自動的に更新を確認する"
Basic.Settings.General.WarnBeforeStartingStream="配信を開始するときに確認ダイアログを表示する"
Basic.Settings.General.WarnBeforeStoppingStream="配信を停止するときに確認ダイアログを表示する"
+Basic.Settings.General.Projectors="プロジェクター"
Basic.Settings.General.HideProjectorCursor="プロジェクター上のカーソルを非表示にする"
Basic.Settings.General.ProjectorAlwaysOnTop="プロジェクタを常に手前に表示させる"
Basic.Settings.General.Snapping="ソース配置のスナップ"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="他のソースにソースをスナッ
Basic.Settings.General.SnapDistance="スナップ感度"
Basic.Settings.General.RecordWhenStreaming="配信時に自動的に録画"
Basic.Settings.General.KeepRecordingWhenStreamStops="配信が停止しても録画を継続"
-Basic.Settings.General.SysTrayEnabled="システムトレイアイコンを有効にする"
+Basic.Settings.General.ReplayBufferWhileStreaming="配信時に自動的にリプレイバッファーを開始"
+Basic.Settings.General.KeepReplayBufferStreamStops="配信停止時にリプレイバッファーをアクティブにしておく"
+Basic.Settings.General.SysTray="システムトレイ"
Basic.Settings.General.SysTrayWhenStarted="起動時にシステムトレイへ最小化"
+Basic.Settings.General.SystemTrayHideMinimize="タスクバーの代わりにシステムトレイに常に最小化する"
+Basic.Settings.General.SaveProjectors="終了時にプロジェクターを保存する"
Basic.Settings.Stream="配信"
Basic.Settings.Stream.StreamType="配信種別"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="出力モード"
Basic.Settings.Output.Mode.Simple="基本"
Basic.Settings.Output.Mode.Adv="詳細"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg の出力"
+Basic.Settings.Output.UseReplayBuffer="リプレイバッファーを有効にする"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="最大リプレイ時間 (秒)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="最大メモリ (メガバイト)"
+Basic.Settings.Output.ReplayBuffer.Estimate="概算メモリ使用量: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="メモリ使用量を見積もることができません。 最大メモリ制限を設定してください。"
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(注: ホットキーでリプレイバッファーのホットキーを設定してください)"
+Basic.Settings.Output.ReplayBuffer.Prefix="リプレイバッファーのファイル名の接頭辞"
+Basic.Settings.Output.ReplayBuffer.Suffix="接尾辞"
Basic.Settings.Output.Simple.SavePath="録画ファイルのパス"
Basic.Settings.Output.Simple.RecordingQuality="録画品質"
Basic.Settings.Output.Simple.RecordingQuality.Stream="配信と同じ"
@@ -391,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="トラック 1"
Basic.Settings.Output.Adv.Audio.Track2="トラック 2"
Basic.Settings.Output.Adv.Audio.Track3="トラック 3"
Basic.Settings.Output.Adv.Audio.Track4="トラック 4"
+Basic.Settings.Output.Adv.Audio.Track5="トラック 5"
+Basic.Settings.Output.Adv.Audio.Track6="トラック 6"
Basic.Settings.Output.Adv.Recording="録画"
Basic.Settings.Output.Adv.Recording.Type="種別"
@@ -418,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="映像エンコーダ設定 (
Basic.Settings.Output.Adv.FFmpeg.AEncoder="音声エンコーダ"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="音声エンコーダ設定 (ある場合)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="マルチプレクサーの設定 (ある場合)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="キーフレーム間隔 (フレーム)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="すべてのコーデックを表示 (潜在的に互換性がない場合でも)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -471,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV 色空間"
Basic.Settings.Advanced.Video.ColorRange="YUV 色範囲"
Basic.Settings.Advanced.Video.ColorRange.Partial="一部"
Basic.Settings.Advanced.Video.ColorRange.Full="全部"
+Basic.Settings.Advanced.Audio.MonitoringDevice="音声モニタリングデバイス"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="既定"
Basic.Settings.Advanced.StreamDelay="遅延配信"
Basic.Settings.Advanced.StreamDelay.Duration="継続時間 (秒)"
Basic.Settings.Advanced.StreamDelay.Preserve="再接続時にカットオフポイントを保持する (増加遅延)"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="概算メモリ使用量: %1 MB"
Basic.Settings.Advanced.Network="ネットワーク"
Basic.Settings.Advanced.Network.BindToIP="IP選択"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="新しいネットワークコードを有効にする"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="低遅延モード"
Basic.AdvAudio="オーディオの詳細プロパティ"
Basic.AdvAudio.Name="名称"
@@ -484,15 +553,15 @@ Basic.AdvAudio.Volume="音量 (%)"
Basic.AdvAudio.Mono="モノラルにダウンミックス"
Basic.AdvAudio.Panning="パンニング"
Basic.AdvAudio.SyncOffset="同期オフセット (ミリ秒)"
+Basic.AdvAudio.Monitoring="音声モニタリング"
+Basic.AdvAudio.Monitoring.None="モニターオフ"
+Basic.AdvAudio.Monitoring.MonitorOnly="モニターのみ (出力はミュート)"
+Basic.AdvAudio.Monitoring.Both="モニターと出力"
Basic.AdvAudio.AudioTracks="トラック"
Basic.Settings.Hotkeys="ホットキー"
Basic.Settings.Hotkeys.Pair="'%1' との組合せでトグルスイッチとして機能します"
-Basic.Hotkeys.StartStreaming="配信開始"
-Basic.Hotkeys.StopStreaming="配信終了"
-Basic.Hotkeys.StartRecording="録画開始"
-Basic.Hotkeys.StopRecording="録画終了"
Basic.Hotkeys.SelectScene="シーン切り替え"
Basic.SystemTray.Show="表示"
@@ -546,4 +615,5 @@ SceneItemHide="'%1' を非表示"
OutputWarnings.NoTracksSelected="少なくとも 1 つのトラックを選択する必要があります"
OutputWarnings.MultiTrackRecording="警告: 特定のフォーマット (FLVなど) は1つの録画で複数のトラックをサポートしていません"
+OutputWarnings.MP4Recording="警告: ファイルをファイナライズ出来ない場合 (例えば、BSOD、電力損失などの結果として) はMP4に保存された録画は回復不能になります。 複数の音声トラックを録画する場合はMKVの利用を検討して録画の終了後にMP4に再多重化してください。(ファイル -> 録画の再多重化)"
diff --git a/UI/data/locale/ko-KR.ini b/UI/data/locale/ko-KR.ini
index 50353f0..9c62f0e 100644
--- a/UI/data/locale/ko-KR.ini
+++ b/UI/data/locale/ko-KR.ini
@@ -49,6 +49,26 @@ Right="오른쪽"
Top="위"
Bottom="아래"
Reset="초기화"
+Hours="시"
+Minutes="분"
+Seconds="초"
+Deprecated="사용하지 않음"
+ReplayBuffer="리플레이 버퍼"
+Import="가져오기"
+Export="내보내기"
+
+Updater.Title="사용가능한 판올림이 있습니다"
+Updater.Text="새 판올림이 준비되었습니다:"
+Updater.UpdateNow="지금 판올림하기"
+Updater.RemindMeLater="나중에 다시 알림"
+Updater.Skip="이번 버전 건너뛰기"
+Updater.Running.Title="현재 활성화된 프로그램"
+Updater.Running.Text="판올림 전에 활성화되어 있는 출력을 먼저 꺼주세요"
+Updater.NoUpdatesAvailable.Title="가능한 판올림이 없습니다"
+Updater.NoUpdatesAvailable.Text="현재 사용가능한 판올림이 없습니다"
+Updater.FailedToLaunch="판올림 도우미를 실행할 수 없습니다"
+Updater.GameCaptureActive.Title="게임 캡쳐 기능이 활성화 중"
+Updater.GameCaptureActive.Text="게임 캡쳐 기능을 현재 사용 중입니다. 캡쳐 중인 게임이나 프로그램을 종료(혹은 윈도우를 재시작) 한 다음 다시 시도하세요."
QuickTransitions.SwapScenes="전환 후 미리 보기/출력 장면을 교체"
QuickTransitions.SwapScenesTT="(만약 출력 쪽 원본 장면이 있을 때) 전환 작업 이후 미리 보기와 출력 장면을 교체합니다. \n출력 쪽 원본 장면에서 변경한 내용은 사라지지 않습니다."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="제거 확인"
ConfirmRemove.Text="'$1'을 정말로 제거하시겠습니까?"
ConfirmRemove.TextMultiple="정말로 %1 개의 항목을 제거하겠습니까?"
+Output.StartStreamFailed="방송을 시작하지 못했습니다"
+Output.StartRecordingFailed="녹화를 시작하지 못했습니다"
+Output.StartReplayFailed="리플레이 버퍼를 시작하지 못했습니다"
+Output.StartFailedGeneric="출력을 시작하지 못했습니다. 기록 파일을 확인하십시오.\n\n참고: NVENC 혹은 AMD 인코더를 사용하고 있다면 드라이버를 최신 버전으로 유지하십시오."
+
Output.ConnectFail.Title="연결에 실패했음"
Output.ConnectFail.BadPath="잘못된 경로 혹은 연결 주소입니다. 유효한 값인지 설정을 확인하시기 바랍니다. "
Output.ConnectFail.ConnectFailed="서버에 연결하지 못했습니다"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="디스크 공간 부족"
Output.RecordNoSpace.Msg="녹화를 계속하기 위한 디스크 공간이 부족합니다."
Output.RecordError.Title="녹화 오류"
Output.RecordError.Msg="녹화 중 예기치 못한 오류가 발생했습니다."
+Output.ReplayBuffer.NoHotkey.Title="단축키가 없습니다!"
+Output.ReplayBuffer.NoHotkey.Msg="리플레이를 저장하는 단축키를 지정하지 않았습니다. 리플레이 녹화 기능을 사용하려면 \"저장\" 단축키를 지정하십시오."
Output.BadPath.Title="잘못된 파일 경로"
Output.BadPath.Text="설정된 출력 파일 경로가 올바르지 않습니다. 경로가 제대로 설정이 되었는지 확인하십시오. "
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="야디프 2x"
Deinterlacing.TopFieldFirst="상위 필드 우선"
Deinterlacing.BottomFieldFirst="하단 필드 우선"
+VolControl.SliderUnmuted="'%1'의 음량 조절: %2"
+VolControl.SliderMuted="'%1'의 음량 조절: %2 (현재 음소거)"
+VolControl.Mute="음소거 '%1'"
+VolControl.Properties="'%1' 속성"
+
Basic.Main.AddSceneDlg.Title="장면 추가"
Basic.Main.AddSceneDlg.Text="장면의 이름을 입력하십시오"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="장면 목록:"
Basic.Main.Sources="소스 목록:"
Basic.Main.Connecting="연결 중..."
Basic.Main.StartRecording="녹화 시작"
+Basic.Main.StartReplayBuffer="리플레이 버퍼 시작"
Basic.Main.StartStreaming="방송 시작"
Basic.Main.StopRecording="녹화 중단"
Basic.Main.StoppingRecording="녹화를 중단합니다...."
+Basic.Main.StopReplayBuffer="리플레이 버퍼 중단"
+Basic.Main.StoppingReplayBuffer="리플레이 버퍼를 멈추고 있습니다..,"
Basic.Main.StopStreaming="방송 중단"
Basic.Main.StoppingStreaming="방송을 중지합니다..."
Basic.Main.ForceStopStreaming="방송 중지(지연된 분량도 마무리없이 즉시 송출 중단)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="다시 실행(&R)"
Basic.MainMenu.Edit.UndoAction="$1 실행 취소(&U)"
Basic.MainMenu.Edit.RedoAction="$1 되돌리기(&R)"
Basic.MainMenu.Edit.LockPreview="미리보기 잠금(&L)"
+Basic.MainMenu.Edit.Scale="미리보기 비율(&S)"
+Basic.MainMenu.Edit.Scale.Window="창에 맞추기"
+Basic.MainMenu.Edit.Scale.Canvas="캔버스 (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="출력 (%1x%2)"
Basic.MainMenu.Edit.Transform="변환(&T)"
Basic.MainMenu.Edit.Transform.EditTransform="변환 편집(&E)"
+Basic.MainMenu.Edit.Transform.CopyTransform="변환 복사"
+Basic.MainMenu.Edit.Transform.PasteTransform="변환 붙여넣기"
Basic.MainMenu.Edit.Transform.ResetTransform="변환 초기화(&R)"
Basic.MainMenu.Edit.Transform.Rotate90CW="시계 방향으로 90도 회전"
Basic.MainMenu.Edit.Transform.Rotate90CCW="반시계 방향으로 90도 회전"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="상태 표시줄(&S)"
Basic.MainMenu.SceneCollection="장면 모음(&S)"
Basic.MainMenu.Profile="프로파일(&P)"
+Basic.MainMenu.Profile.Import="프로파일 가져오기"
+Basic.MainMenu.Profile.Export="프로파일 내보내기"
+Basic.MainMenu.SceneCollection.Import="장면 모음 가져오기"
+Basic.MainMenu.SceneCollection.Export="장면 모음 내보내기"
+Basic.MainMenu.Profile.Exists="그 프로파일은 이미 존재합니다."
+Basic.MainMenu.SceneCollection.Exists="그 장면 모음은 이미 존재합니다."
Basic.MainMenu.Tools="도구(&T)"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="저장하지 않은 설정이 있습니다. 저장하시
Basic.Settings.General="일반"
Basic.Settings.General.Theme="테마"
Basic.Settings.General.Language="언어"
+Basic.Settings.General.EnableAutoUpdates="프로그램을 시작할 때 자동으로 판올림이 있나 확인"
Basic.Settings.General.WarnBeforeStartingStream="방송을 시작할 때 확인 대화 상자 표시"
Basic.Settings.General.WarnBeforeStoppingStream="방송을 중단할 때 확인 대화 상자 표시"
+Basic.Settings.General.Projectors="프로젝터"
Basic.Settings.General.HideProjectorCursor="프로젝터 위 커서 숨기기"
Basic.Settings.General.ProjectorAlwaysOnTop="프로젝터를 항상 위로"
Basic.Settings.General.Snapping="소스를 자석처럼 달라붙여서 정렬"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="소스를 다른 소스에 붙임"
Basic.Settings.General.SnapDistance="자석 감도"
Basic.Settings.General.RecordWhenStreaming="방송 시 자동으로 녹화"
Basic.Settings.General.KeepRecordingWhenStreamStops="방송을 중단하더라도 녹화는 유지"
-Basic.Settings.General.SysTrayEnabled="시스템 트레이 아이콘 활성화"
+Basic.Settings.General.ReplayBufferWhileStreaming="방송 시 리플레이 버퍼를 자동으로 시작"
+Basic.Settings.General.KeepReplayBufferStreamStops="방송 중단에도 리플레이 버퍼를 계속 활성화"
+Basic.Settings.General.SysTray="시스템 트레이"
Basic.Settings.General.SysTrayWhenStarted="시작할 때 시스템 트레이로 최소화"
+Basic.Settings.General.SystemTrayHideMinimize="작업 표시줄 대신 시스템 트레이에 항상 최소화"
+Basic.Settings.General.SaveProjectors="종료 시 프로젝터 저장"
Basic.Settings.Stream="방송"
Basic.Settings.Stream.StreamType="방송 형식"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="출력 모드"
Basic.Settings.Output.Mode.Simple="단순"
Basic.Settings.Output.Mode.Adv="고급"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg 출력"
+Basic.Settings.Output.UseReplayBuffer="리플레이 버퍼 활성화"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="최대 리플레이 시간 (초 단위)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="최대 메모리 (메가바이트 단위)"
+Basic.Settings.Output.ReplayBuffer.Estimate="예상되는 메모리 사용량: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="메모리 사용량을 계산할 수 없습니다. 최대 메모리 사용량을 설정하세요."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(참고: 단축키 설정에서 리플레이 버퍼의 단축키를 꼭 지정하세요)"
+Basic.Settings.Output.ReplayBuffer.Prefix="리플레이 버퍼 파일이름 접두사"
+Basic.Settings.Output.ReplayBuffer.Suffix="접미사"
Basic.Settings.Output.Simple.SavePath="녹화 경로"
Basic.Settings.Output.Simple.RecordingQuality="녹화 품질"
Basic.Settings.Output.Simple.RecordingQuality.Stream="방송 품질과 동일하게"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="무손실 품질 설정 경고
Basic.Settings.Output.Simple.Warn.MultipleQSV="경고: 방송과 녹화를 동시에 하고 있을 때 여러 개의 독립된 QSV 인코더를 사용할 수 없습니다. 두 작업을 동시에 하려면 녹화 혹은 방송 인코더 둘 중 하나를 바꿔야 합니다."
Basic.Settings.Output.Simple.Encoder.Software="소프트웨어 (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="하드웨어 (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="하드웨어 (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="하드웨어 (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="소프트웨어 (x264 CPU 부담이 적지만 파일 크기가 증가)"
Basic.Settings.Output.VideoBitrate="비디오 비트레이트"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="트랙 1"
Basic.Settings.Output.Adv.Audio.Track2="트랙 2"
Basic.Settings.Output.Adv.Audio.Track3="트랙 3"
Basic.Settings.Output.Adv.Audio.Track4="트랙 4"
+Basic.Settings.Output.Adv.Audio.Track5="트랙 5"
+Basic.Settings.Output.Adv.Audio.Track6="트랙 6"
Basic.Settings.Output.Adv.Recording="녹화"
Basic.Settings.Output.Adv.Recording.Type="형식"
@@ -417,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="비디오 인코더 설정 (
Basic.Settings.Output.Adv.FFmpeg.AEncoder="오디오 인코더"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="오디오 인코더 설정 (지원되는 경우)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="다중화 설정 (제공되는 경우)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="키프레임 간격 (프레임 단위)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="모든 코덱을 표시 (호환이 안되는 것도 포함)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV 색 공간"
Basic.Settings.Advanced.Video.ColorRange="YUV 색상 범위"
Basic.Settings.Advanced.Video.ColorRange.Partial="부분"
Basic.Settings.Advanced.Video.ColorRange.Full="전체"
+Basic.Settings.Advanced.Audio.MonitoringDevice="오디오 모니터링 장치"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="기본값"
Basic.Settings.Advanced.StreamDelay="방송 지연"
Basic.Settings.Advanced.StreamDelay.Duration="기간 (초)"
Basic.Settings.Advanced.StreamDelay.Preserve="재접속 시 잘려나간 지점 보관 (지연시간 증가)"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="예상되는 메모리 사용량: %1 MB"
Basic.Settings.Advanced.Network="네트워크"
Basic.Settings.Advanced.Network.BindToIP="IP에 고정"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="새로운 네트워크 코드 활성화"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="짧은 지연시간 모드"
Basic.AdvAudio="오디오 고급 설정"
Basic.AdvAudio.Name="이름"
@@ -483,15 +553,15 @@ Basic.AdvAudio.Volume="볼륨 (%)"
Basic.AdvAudio.Mono="모노로 강제 송출"
Basic.AdvAudio.Panning="패닝"
Basic.AdvAudio.SyncOffset="싱크 오프셋 (ms)"
+Basic.AdvAudio.Monitoring="오디오 모니터링"
+Basic.AdvAudio.Monitoring.None="모니터링 끔"
+Basic.AdvAudio.Monitoring.MonitorOnly="모니터링만 (출력은 제거)"
+Basic.AdvAudio.Monitoring.Both="모니터링과 출력"
Basic.AdvAudio.AudioTracks="트랙"
Basic.Settings.Hotkeys="단축키"
Basic.Settings.Hotkeys.Pair="'%1'과 공유하는 키 조합을 토글 형식으로 설정"
-Basic.Hotkeys.StartStreaming="방송 시작"
-Basic.Hotkeys.StopStreaming="방송 중단"
-Basic.Hotkeys.StartRecording="녹화 시작"
-Basic.Hotkeys.StopRecording="녹화 중단"
Basic.Hotkeys.SelectScene="장면 전환"
Basic.SystemTray.Show="보이기"
@@ -545,4 +615,5 @@ SceneItemHide="'%1' 숨기기"
OutputWarnings.NoTracksSelected="최소 하나의 트랙을 선택해야 합니다"
OutputWarnings.MultiTrackRecording="경고: 일부 형식(예를 들어 FLV)은 녹화 하나에 여러 개의 트랙을 지원하지 않습니다"
+OutputWarnings.MP4Recording="경고: MP4로 녹화를 하면 파일이 마무리가 되지 않았을 때 (예를 들어 컴퓨터가 급작스럽게 꺼지거나 블루 스크린 오류가 일어나는 경우) 복구할 수 없습니다. 여러 개의 오디오 트랙을 녹음하고 싶다면 MKV 확장자로 녹화 한 뒤 재다중화 작업을 통해 mp4로 전환하십시오. (파일->재다중화 녹화)"
diff --git a/UI/data/locale/lt-LT.ini b/UI/data/locale/lt-LT.ini
index d3f837b..ad0fa96 100644
--- a/UI/data/locale/lt-LT.ini
+++ b/UI/data/locale/lt-LT.ini
@@ -49,6 +49,7 @@ Right="Iš dešinės"
Top="Iš viršaus"
Bottom="Iš apačios"
+
QuickTransitions.SwapScenes="Sukeisti Peržiūros/Išvesties scenas po Perėjimo"
QuickTransitions.SwapScenesTT="Sukeičia peržiūros ir išvesties scenas po perėjimo įvykdymo (jei originali išvesties scena vis dar egzistuoja).\nTai neatšauks jokių pakeitimų kurie galima buvo atlikti originalioje išvesties scenoje."
QuickTransitions.DuplicateScene="Dubliuoti Sceną"
@@ -86,6 +87,7 @@ ConfirmExit.Text="OBS metu yra aktyvus. Visos transliacijos/įrašymai bus išju
ConfirmRemove.Title="Pašalinimo patvirtinimas"
ConfirmRemove.Text="Ar tikrai norite pašalinti '$1'?"
+
Output.ConnectFail.Title="Nepavyko prisijungti"
Output.ConnectFail.BadPath="Neteisingas kelias arba jungimosi URL. Prašome patikrinti nustatymus ir įsitikinti, kad jie teisingi."
Output.ConnectFail.ConnectFailed="Nepavyko prisijungti prie serverio"
@@ -159,6 +161,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Piršutinis puskadris pirmas"
Deinterlacing.BottomFieldFirst="Apatinis puskadris pirmas"
+
Basic.Main.AddSceneDlg.Title="Pridėti sceną"
Basic.Main.AddSceneDlg.Text="Įveskite pasirinktą scenos pavadinimą"
diff --git a/UI/data/locale/ms-MY.ini b/UI/data/locale/ms-MY.ini
index 3970dbb..82da14e 100644
--- a/UI/data/locale/ms-MY.ini
+++ b/UI/data/locale/ms-MY.ini
@@ -23,11 +23,11 @@ Settings="Tetapan"
Display="Paparan"
Name="Nama"
Exit="Keluar"
-Mixer="Pengadun(suara)"
+Mixer="Pengadun suara"
Browse="Cari"
Mono="Mono"
Stereo="Stereo"
-DroppedFrames="Gambar-gambar Terjatuh %1 (%2%)"
+DroppedFrames="%1 Gambar Hilang (%2%)"
PreviewProjector="Paparan Projektor penuh (Pratonton)"
SceneProjector="Paparan Projektor penuh (Adegan)"
SourceProjector="Paparan Projektor penuh (Sumber)"
@@ -36,29 +36,34 @@ Revert="Ubah kembali"
Show="Tunjuk"
Hide="Sembunyi"
Untitled="Tiada tajuk"
-New="Baru"
-Duplicate="Salin"
+New="Baharu"
+Duplicate="Salin semula"
Enable="Benarkan"
-DisableOSXVSync="Nyahaktifkan OSX V-Sync"
-ResetOSXVSyncOnExit="Tetapkan semula OSX V-Sync apabila keluar"
-HighResourceUsage="Pengekodan terbeban! Cuba turunkan tetapan video ataupun gunakan pratetapan pengekodan yang lebih cepat."
+DisableOSXVSync="Nyahaktifkan V-Sync OSX"
+ResetOSXVSyncOnExit="Set semula OSX V-Sync apabila keluar"
+HighResourceUsage="Pengekodan terbeban! Cuba turunkan tetapan video ataupun gunakan pratetap pengekodan yang lebih laju."
Transition="Peralihan"
QuickTransitions="Peralihan Pantas"
Left="Kiri"
Right="Kanan"
Top="Atas"
Bottom="Bawah"
+Reset="Set semula"
+Hours="Jam"
+Minutes="Minit"
+Seconds="Saat"
-QuickTransitions.SwapScenes="Tukar Pratonton/Output Adegan-adegan Selepas Peralihan"
-QuickTransitions.SwapScenesTT="Menukarkan pratonton dan output adegan-adegan sleeps peralihan(jika output adegan mash wujud).\nIni tidak akan mengundurkan semarang perubahan yang mungkin telah dibuat pada output adegan yang asal."
+
+QuickTransitions.SwapScenes="Tukar Pratonton/Pengeluaran Adegan Selepas Peralihan"
+QuickTransitions.SwapScenesTT="Menukarkan pratonton dan pengeluaran adegan-adegan selepas peralihan(jika pengeluaran adegan mash wujud).\nIni tidak akan mengundurkan sebarang perubahan yang mungkin telah dilakukan pada pengeluaran adegan yang asal."
QuickTransitions.DuplicateScene="Klonkan Adegan"
-QuickTransitions.DuplicateSceneTT="Apabila menyunting adegan yang sama, ini membolehkan penyuntingan perubahan/keterlihatan tanpa mengubah output..\nUntuk edit sifat-sifat adegan-adegan tanpa mengubah suai output, aktifkan 'Klonkan Adegan'.\nPengubahan nilai ini akan menetapkan semula output adegan (jika adegan masih wujud)."
+QuickTransitions.DuplicateSceneTT="Apabila menyunting adegan yang sama, ini membolehkan penyuntingan perubahan/keterlihatan tanpa mengubah pengeluaran.\nUntuk edit sifat-sifat adegan tanpa mengubah suai pengeluaran, aktifkan 'Klonkan Adegan'.\nPengubahan nilai ini akan menetapkan semula pengeluaran adegan (jika adegan masih wujud)."
QuickTransitions.EditProperties="Klonkan Sumber"
-QuickTransitions.EditPropertiesTT="Apabila menyunting adegan yang sama, ini membolehkan penyuntingan sumber-sumber tanpa mengubah output.\nIni hanya boleh dilakukan jika 'Klonkan Adegan' diaktifkan.\nSebahagian sumber (seperti sumber-sumber tangkapan atau media) tidak menyokong tetapan ini dan tidak boleh disunting secara berasingan.\nPenukaran nilai ini akan menetapkan semula output adegan yang sedang digunakan (jika adegan masih wujud).\n\nAmaran: Kerana sumber-sumber akan diklonkan, ini mungkin memerlukan penambahan sumber-sumber sistem/video."
+QuickTransitions.EditPropertiesTT="Apabila menyunting adegan yang sama, ini membolehkan penyuntingan sumber-sumber tanpa mengubah pengeluaran.\nIni hanya boleh dilakukan jika 'Klonkan Adegan' diaktifkan.\nSebahagian sumber (seperti sumber-sumber penangkapan atau media) tidak menyokong tetapan ini dan tidak boleh disunting secara berasingan.\nPenukaran nilai ini akan menetapkan semula pengeluaran adegan yang sedang digunakan (jika adegan masih wujud).\n\nAmaran: Pilihan ini mungkin memerlukan sumber-sumber sistem/audio tambahan kerana sumber-sumber akan diklonkan."
QuickTransitions.HotkeyName="Peralihan Pantas: %1"
-Basic.AddTransition="Tambah Peralihan Yang Boleh Diubahsuai"
-Basic.RemoveTransition="Buang Peralihan Yang Boleh Diubahsuai"
+Basic.AddTransition="Tambah Peralihan yang Boleh Diubahsuai"
+Basic.RemoveTransition="Buang Peralihan yang Boleh Diubahsuai"
Basic.TransitionProperties="Sifat-sifat Peralihan"
Basic.SceneTransitions="Peralihan-peralihan Adegan"
Basic.TransitionDuration="Tempoh"
@@ -87,24 +92,27 @@ ConfirmExit.Text="OBS kini sedang aktif. Semua 'stream'/rakaman akan ditutup. Ad
ConfirmRemove.Title="Pengesahan untuk Buang"
ConfirmRemove.Text="Adakah anda pasti untuk buang '$1'?"
+ConfirmRemove.TextMultiple="Adakah anda yakin untuk buang %1 barang?"
+
Output.ConnectFail.Title="Penyambungan gagal"
Output.ConnectFail.BadPath="Sambungan URL atau Laluan yang tidak sah. Sila semak semula tetapan anda to mengesahkan bahawa semuanya sah."
Output.ConnectFail.ConnectFailed="Penyambungan ke pelayan gagal"
+Output.ConnectFail.InvalidStream="Tidak dapat mencapai saluran yang ditetapkan/kata kunci 'stream', sila semak semula kata kunci 'stream'. Jika ia betul, kemungkinan ada masalah menyambung kepada pelayan."
Output.ConnectFail.Error="Ralat tidak dijangka berlaku sewaktu percubaan menyambung ke pelayan. Maklumat lanjut di dalam fail log."
Output.ConnectFail.Disconnected="Terputus daripada pelayan."
Output.RecordFail.Title="Gagal memulakan rakaman"
-Output.RecordFail.Unsupported="Output format adalah tidak disokong atau tidak membenarkan lebih daripada satu 'audio track'. Sila semak tetapan anda dan cuba lagi."
+Output.RecordFail.Unsupported="Format pengeluaran tidak disokong atau tidak membenarkan lebih daripada satu trek audio. Sila semak tetapan anda dan cuba lagi."
Output.RecordNoSpace.Title="Ruang simpanan tidak cukup"
Output.RecordNoSpace.Msg="Tiada ruang simpanan yang cukup untuk meneruskan rakaman."
Output.RecordError.Title="Ralat rakaman"
Output.RecordError.Msg="Ralat yang tidak ditetapkan berlaku semasa rakaman."
Output.BadPath.Title="Laluan Fail Rosak"
-Output.BadPath.Text="Laluan output fail yang dikonfigurasikan tidak sah.Sila semak semula tetapan anda untuk mengesahkan laluan fail yang sah telah ditetapkan."
+Output.BadPath.Text="Laluan pengeluaran fail yang dikonfigurasikan tidak sah. Sila semak semula tetapan anda untuk mengesahkan laluan fail yang sah telah ditetapkan."
-LogReturnDialog="Memuat naik Log Berjaya"
+LogReturnDialog="Muat naik Log Berjaya"
LogReturnDialog.CopyURL="Salin URL"
LogReturnDialog.ErrorUploadingLog="Ralat memuat naikkan fail log"
@@ -115,30 +123,52 @@ LicenseAgreement.IAgree="Saya Setuju"
LicenseAgreement.Exit="Keluar"
Remux.SourceFile="Rakaman OBS"
-Remux.TargetFile="Fail sasaran"
+Remux.TargetFile="Fail Sasaran"
+Remux.Remux="Tukar format"
Remux.OBSRecording="Rakaman OBS"
+Remux.FinishedTitle="Penukaran format selesai"
+Remux.Finished="Format rakaman ditukar"
+Remux.FinishedError="Format rakaman ditukar, tetapi fail itu mungkin tidak lengkap"
Remux.SelectRecording="Pilih Rakaman OBS …"
Remux.SelectTarget="Pilih fail sasaran …"
Remux.FileExistsTitle="Fail sasaran wujud"
Remux.FileExists="Fail sasaran wujud, adakah anda mahu gantikannya?"
+Remux.ExitUnfinishedTitle="Penukaran format sedang dijalankan"
+Remux.ExitUnfinished="Penukaran format masih belum selesai, menghentikannya sekarang boleh menyebabkan fail sasaran tidak boleh digunakan.\nAdakah anda pasti untuk memberhentikan proses ini?"
UpdateAvailable="Ada Versi Baru"
UpdateAvailable.Text="Versi %1.%2.%3 kini ada. Klik sini untuk memuat turun "
Basic.DesktopDevice1="Audio Desktop"
-Basic.DesktopDevice2="Audio Desktop"
+Basic.DesktopDevice2="Audio Desktop 2"
Basic.AuxDevice1="Mic/Aux"
Basic.AuxDevice2="Mic/Aux 2"
Basic.AuxDevice3="Mic/Aux 3"
Basic.AuxDevice4="Mic/Aux 4"
Basic.Scene="Adegan"
+Basic.DisplayCapture="Paparan Penuh"
Basic.Main.PreviewConextMenu.Enable="Benarkan Pratonton"
+ScaleFiltering="Skala Tapisan"
+ScaleFiltering.Point="Point"
+ScaleFiltering.Bilinear="Bilinear"
+ScaleFiltering.Bicubic="Bicubic"
+ScaleFiltering.Lanczos="Lanczos"
+Deinterlacing="Deinterlacing"
+Deinterlacing.Discard="Discard"
Deinterlacing.Retro="Retro"
+Deinterlacing.Blend="Blend"
+Deinterlacing.Blend2x="Blend 2x"
Deinterlacing.Linear="Linear"
+Deinterlacing.Linear2x="Linear 2x"
+Deinterlacing.Yadif="Yadif"
+Deinterlacing.Yadif2x="Yadif 2x"
+Deinterlacing.TopFieldFirst="Bahagian Atas Dahulu"
+Deinterlacing.BottomFieldFirst="Bahagian Bawah Dahulu"
+
Basic.Main.AddSceneDlg.Title="Tambah Adegan"
Basic.Main.AddSceneDlg.Text="Sila taip nama adegan"
@@ -170,14 +200,16 @@ Basic.PropertiesWindow.ConfirmTitle="Perubahan Tetapan"
Basic.PropertiesWindow.Confirm="Ada perubahan yang belum disimpan. Adakah anda mahu menyimpannya?"
Basic.PropertiesWindow.NoProperties="Tiada sifat-sifat disediakan"
Basic.PropertiesWindow.AddFiles="Tambah Fail-Fail"
+Basic.PropertiesWindow.AddDir="Tambah Direktori"
Basic.PropertiesWindow.AddURL="Tambah laluan/URL"
+Basic.PropertiesWindow.AddEditableListDir="Tambah direktori ke '%1'"
Basic.PropertiesWindow.AddEditableListFiles="Tambah fail ke '%1'"
Basic.PropertiesWindow.AddEditableListEntry="Tambah entri ke '%1'"
Basic.PropertiesWindow.EditEditableListEntry="Sunting entri daripada '%1'"
-Basic.PropertiesView.FPS.Simple="Nilai-nilai mudah FPS"
-Basic.PropertiesView.FPS.Rational="Nilai-nilai pecahan FPS"
-Basic.PropertiesView.FPS.ValidFPSRanges="Julat sah FPS:"
+Basic.PropertiesView.FPS.Simple="Nilai-nilai FPS mudah"
+Basic.PropertiesView.FPS.Rational="Nilai-nilai FPS pecahan"
+Basic.PropertiesView.FPS.ValidFPSRanges="Julat FPS sah:"
Basic.InteractionWindow="Berinteraksi dengan '%1'"
@@ -201,6 +233,8 @@ Basic.TransformWindow="Pengubahan Item Adegan"
Basic.TransformWindow.Position="Kedudukan"
Basic.TransformWindow.Rotation="Pusingan"
Basic.TransformWindow.Size="Saiz"
+Basic.TransformWindow.Alignment="Kedudukan Penjajaran"
+Basic.TransformWindow.Crop="Potong"
Basic.TransformWindow.Alignment.TopLeft="Kiri Atas"
Basic.TransformWindow.Alignment.TopCenter="Tengah Atas"
@@ -224,13 +258,16 @@ Basic.Main.Connecting="Menyambung..."
Basic.Main.StartRecording="Mula rakaman"
Basic.Main.StartStreaming="Mula 'streaming'"
Basic.Main.StopRecording="Hentikan rakaman"
+Basic.Main.StoppingRecording="Menghentikan rakaman..."
Basic.Main.StopStreaming="Hentikan 'streaming'"
+Basic.Main.StoppingStreaming="Menghentikan 'streaming'..."
Basic.Main.ForceStopStreaming="Berhenti 'streaming' (buang kelewatan)"
Basic.MainMenu.File="&Fail"
Basic.MainMenu.File.Export="&Export"
Basic.MainMenu.File.Import="&Import"
Basic.MainMenu.File.ShowRecordings="Papar &Rakaman"
+Basic.MainMenu.File.Remux="Format& rakaman"
Basic.MainMenu.File.Settings="&Tetapan"
Basic.MainMenu.File.ShowSettingsFolder="Tunjukkan Folder Tetapan"
Basic.MainMenu.File.ShowProfileFolder="Tunjukkan Folder Profil"
@@ -242,11 +279,14 @@ Basic.MainMenu.Edit.Undo="&Ubah Balik"
Basic.MainMenu.Edit.Redo="Buat Semula (&R)"
Basic.MainMenu.Edit.UndoAction="&Ubah Balik $1"
Basic.MainMenu.Edit.RedoAction="&Ubah Semula $1"
+Basic.MainMenu.Edit.LockPreview="&Kunci Pratonton"
Basic.MainMenu.Edit.Transform="&Ubah"
Basic.MainMenu.Edit.Transform.EditTransform="&Sunting Perubahan..."
Basic.MainMenu.Edit.Transform.Rotate90CW="Putarkan 90 darjah mengikut arah jam"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Putarkan 90 darjah melawan arah jam"
Basic.MainMenu.Edit.Transform.Rotate180="Putarkan 180 darjah"
+Basic.MainMenu.Edit.Transform.FlipHorizontal="Flip secara &Mendatar"
+Basic.MainMenu.Edit.Transform.FlipVertical="Flip secara &Menegak"
Basic.MainMenu.Edit.Transform.FitToScreen="&Muat di skrin"
Basic.MainMenu.Edit.Transform.StretchToScreen="&Regangkan ke skrin"
Basic.MainMenu.Edit.Order.MoveUp="Gerakkan ke &atas"
@@ -260,8 +300,11 @@ Basic.MainMenu.Help.Website="Lawat laman &Web"
Basic.MainMenu.Help.Logs="Fail &Log"
Basic.MainMenu.Help.Logs.ShowLogs="&Tunjukkan Fail-Fail Log"
Basic.MainMenu.Help.Logs.UploadCurrentLog="Muat naik Fail Log &Kini"
+Basic.MainMenu.Help.Logs.UploadLastLog="Muat naik &Fail Log Terakhir"
+Basic.MainMenu.Help.Logs.ViewCurrentLog="&Paparkan Log Semasa"
Basic.MainMenu.Help.CheckForUpdates="Semak Versi Baharu"
+Basic.Settings.ProgramRestart="Program ini mesti dimulakan semula untuk tetapan-tetapan ini berkesan."
Basic.Settings.ConfirmTitle="Sahkan Perubahan"
Basic.Settings.Confirm="Anda mempunyai perubahan yang tidak disimpan. Simpan perubahan?"
@@ -270,38 +313,109 @@ Basic.Settings.General.Theme="Tema"
Basic.Settings.General.Language="Bahasa"
Basic.Settings.General.WarnBeforeStartingStream="Tunjukkan dialog pengesahan ketika memulakan 'stream'"
Basic.Settings.General.WarnBeforeStoppingStream="Tunjukkan dialog pengesahan ketika menghentikan 'stream'"
+Basic.Settings.General.HideProjectorCursor="Sembunyikan tetikus atas projektor"
+Basic.Settings.General.ProjectorAlwaysOnTop="Jadikan projektor sentiasa di atas"
+Basic.Settings.General.SnapDistance="Kepekaan 'snap'"
+Basic.Settings.General.RecordWhenStreaming="Rakam apabila 'streaming' secara automatik"
+Basic.Settings.General.KeepRecordingWhenStreamStops="Tetap rakam selepas 'stream' berhenti"
Basic.Settings.Stream="'Stream'"
Basic.Settings.Stream.StreamType="Jenis 'Stream'"
+Basic.Settings.Output="Hasil"
Basic.Settings.Output.Format="Format Rakaman"
Basic.Settings.Output.SelectFile="Pilih Fail Rakaman"
+Basic.Settings.Output.EnforceBitrate="Kuatkuasakan had nilai bit perkhidmatan 'streaming'"
+Basic.Settings.Output.Mode.Simple="Mudah"
+Basic.Settings.Output.Mode.Adv="Lanjutan"
Basic.Settings.Output.Simple.RecordingQuality="Kualiti Rakaman"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Sama seperti 'stream'"
Basic.Settings.Output.Simple.Encoder.Software="Perisian (x264)"
+Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)"
+Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)"
+Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (Preset x264: pengunaan CPU rendah, menaikkan saiz fail)"
+Basic.Settings.Output.VideoBitrate="Nilai Bit Video"
+Basic.Settings.Output.AudioBitrate="Nilai Bit Audio"
Basic.Settings.Output.Reconnect="Sambung semula secara automatik"
Basic.Settings.Output.RetryDelay="Kelewatan Percubaan (saat)"
Basic.Settings.Output.MaxRetries="Cubaan Maksimum"
+Basic.Settings.Output.Adv.AudioTrack="Trek Audio"
+Basic.Settings.Output.Adv.Streaming="'Streaming'"
+Basic.Settings.Output.Adv.Audio.Track1="Trek 1"
+Basic.Settings.Output.Adv.Audio.Track2="Trek 2"
+Basic.Settings.Output.Adv.Audio.Track3="Trek 3"
+Basic.Settings.Output.Adv.Audio.Track4="Trek 4"
Basic.Settings.Output.Adv.Recording="Rakaman"
Basic.Settings.Output.Adv.Recording.Type="Jenis"
+Basic.Settings.Output.Adv.Recording.Type.Standard="Bias"
+Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Gantikan jika fail wujud"
Basic.Settings.Output.Adv.FFmpeg.Type="Jenis Output FFmpeg"
+Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="Semua Fail"
+Basic.Settings.Output.Adv.FFmpeg.SavePathURL="Laluan fail atau URL"
+Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Audio"
+Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Video"
+Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Format Asal"
+Basic.Settings.Audio.EnablePushToMute="Benarkan Tekan-untuk-senyap"
+Basic.Settings.Audio.PushToMuteDelay="Kelewatan Tekan-untuk-senyap"
+Basic.Settings.Audio.EnablePushToTalk="Benarkan Tekan-untuk-cakap"
+Basic.Settings.Audio.PushToTalkDelay="Kelewatan Tekan-untuk-cakap"
+Basic.Settings.Audio.UnknownAudioDevice="[Peranti tidak disambung atau tiada]"
+Basic.Settings.Advanced="Lanjutan"
+Basic.Settings.Advanced.General.ProcessPriority="Keutamaan Proses"
+Basic.Settings.Advanced.General.ProcessPriority.High="Tinggi"
+Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Atas Normal"
+Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal"
Basic.Settings.Advanced.FormatWarning="Amaran:Format warna selain daripada 'NV12' lebih digunakan untuk rakaman,dan tidak disyorkan apabila 'streaming'.'Streaming' mungkin menyebabkan peningkatan penggunaan CPU disebabkan oleh penukaran format warna."
+Basic.Settings.Advanced.Video.ColorFormat="Format Warna"
+Basic.Settings.Advanced.Video.ColorRange.Partial="Sebahagian"
+Basic.Settings.Advanced.Video.ColorRange.Full="Penuh"
+Basic.Settings.Advanced.StreamDelay="Kelewatan 'Stream'"
+Basic.Settings.Advanced.StreamDelay.MemoryUsage="Anggaran Penggunaan Memori: %1 MB"
+Basic.Settings.Advanced.Network="Rangkaian"
+
+Basic.AdvAudio.Name="Nama"
+Basic.AdvAudio.AudioTracks="Trek-trek"
+
+Basic.Settings.Hotkeys="Kekunci Pantas"
+Basic.SystemTray.Show="Papar"
+Basic.SystemTray.Hide="Sembunyi"
+Basic.SystemTray.Message.Reconnecting="Terputus. Menyambung semula..."
-
-
+Hotkeys.Insert="Insert"
+Hotkeys.Delete="Delete"
+Hotkeys.Home="Home"
+Hotkeys.End="End"
+Hotkeys.PageUp="Page Up"
+Hotkeys.PageDown="Page Down"
+Hotkeys.NumLock="Num Lock"
+Hotkeys.ScrollLock="Scroll Lock"
+Hotkeys.CapsLock="Caps Lock"
+Hotkeys.Backspace="Backspace"
+Hotkeys.Tab="Tab"
+Hotkeys.Print="Print"
+Hotkeys.Pause="Pause"
+Hotkeys.Left="Left"
+Hotkeys.Right="Right"
+Hotkeys.Up="Up"
+Hotkeys.Down="Down"
+Hotkeys.Windows="Windows"
Hotkeys.NumpadDecimal="Perpuluhan Numpad"
+Mute="Senyap"
+Push-to-mute="Tekan-untuk-senyap"
+Push-to-talk="Tekan-untuk-cakap"
diff --git a/UI/data/locale/nb-NO.ini b/UI/data/locale/nb-NO.ini
index 1fafc39..c60250b 100644
--- a/UI/data/locale/nb-NO.ini
+++ b/UI/data/locale/nb-NO.ini
@@ -48,6 +48,23 @@ Left="Venstre"
Right="Høyre"
Top="Topp"
Bottom="Bunn"
+Reset="Tilbakestill"
+Hours="Timer"
+Minutes="Minutter"
+Seconds="Sekunder"
+Deprecated="Foreldet"
+ReplayBuffer="Omspill Buffer"
+Import="Importer"
+Export="Eksporter"
+
+Updater.Title="Ny oppdatering tilgjengelig"
+Updater.Text="Det finnes en ny oppdatering:"
+Updater.UpdateNow="Oppdater nå"
+Updater.RemindMeLater="Påminn meg senere"
+Updater.Skip="Hopp over versjon"
+Updater.Running.Title="Programmet er aktiv"
+Updater.NoUpdatesAvailable.Title="Ingen oppdateringer er tilgjengelig"
+Updater.NoUpdatesAvailable.Text="Ingen oppdateringer er tilgjengelig"
QuickTransitions.SwapScenes="Bytt forhåndsvisnings-/utgangsscener etter overgang"
QuickTransitions.SwapScenesTT="Bytter forhåndsvisnings- og utgangsscenen etter overgang, hvis den originale utgangsscenen fortsatt eksisterer.\nDette vil ikke tilbakestille endringer på den originale utgangsscenen."
@@ -87,6 +104,10 @@ ConfirmExit.Text="OBS er aktiv. Alle strømmer og opptak vil bli stoppet. Er du
ConfirmRemove.Title="Bekreft Fjerning"
ConfirmRemove.Text="Er du sikker på at du vil fjerne '$1'?"
+ConfirmRemove.TextMultiple="Er du sikker du ønsker å fjerne %1 filer?"
+
+Output.StartStreamFailed="Kan ikke starte streaming"
+Output.StartRecordingFailed="Kan ikke starte innspillingen"
Output.ConnectFail.Title="Tilkobling misklytes"
Output.ConnectFail.BadPath="Ugyldig filbane eller tilkoblings-URL. Vennligst bekreft at instillingene dine er riktige."
@@ -101,6 +122,8 @@ Output.RecordNoSpace.Title="Ikke nok diskplass"
Output.RecordNoSpace.Msg="Det er ikke nok diskplass til å fortsette opptaket."
Output.RecordError.Title="Innspillingsfeil"
Output.RecordError.Msg="Det oppstod en uspesifisert feil under opptaket."
+Output.ReplayBuffer.NoHotkey.Title="Ingen hurtigtast satt!"
+Output.ReplayBuffer.NoHotkey.Msg="Ingen lagrings hurtigtast satt for omspillings buffer. Venligst sett \"Lagre\" hurtigtasten i bruk for å lagre opptak."
Output.BadPath.Title="Ugyldig Filbane"
Output.BadPath.Text="Den oppgitte fillagringsbanen er ugyldig. Vennligst kontrollér instillingene dine og bekreft at filbanen er gyldig."
@@ -144,6 +167,11 @@ Basic.DisplayCapture="Skjermopptak"
Basic.Main.PreviewConextMenu.Enable="Aktiver forhåndsvisning"
+ScaleFiltering="Skala Filtrering"
+ScaleFiltering.Point="Punkt"
+ScaleFiltering.Bilinear="Bilineær"
+ScaleFiltering.Bicubic="Bikubisk"
+ScaleFiltering.Lanczos="Lanczos"
Deinterlacing="Avsammenfletting"
Deinterlacing.Discard="Forkast"
@@ -157,6 +185,7 @@ Deinterlacing.Yadif2x="Dobbelyadif"
Deinterlacing.TopFieldFirst="Øverste felt først"
Deinterlacing.BottomFieldFirst="Nederste felt først"
+
Basic.Main.AddSceneDlg.Title="Ny Scene"
Basic.Main.AddSceneDlg.Text="Vennligst gi et navn til scenen."
@@ -251,9 +280,12 @@ Basic.Main.Scenes="Scener"
Basic.Main.Sources="Kilder"
Basic.Main.Connecting="Kobler til…"
Basic.Main.StartRecording="Start Opptak"
+Basic.Main.StartReplayBuffer="Start Omspill Buffer"
Basic.Main.StartStreaming="Start Strømming"
Basic.Main.StopRecording="Stopp Opptak"
Basic.Main.StoppingRecording="Stanser innspilling…"
+Basic.Main.StopReplayBuffer="Stopp Omspill Buffer"
+Basic.Main.StoppingReplayBuffer="Stopper Omspill Bufferen..."
Basic.Main.StopStreaming="Stopp Strømming"
Basic.Main.StoppingStreaming="Stanser strøm…"
Basic.Main.ForceStopStreaming="Stopp strømming (forkast forsinkelse)"
@@ -274,8 +306,12 @@ Basic.MainMenu.Edit.Undo="&Angre"
Basic.MainMenu.Edit.Redo="&Gjør om"
Basic.MainMenu.Edit.UndoAction="&Angre $1"
Basic.MainMenu.Edit.RedoAction="&Gjør om $1"
+Basic.MainMenu.Edit.LockPreview="Lås Forhåndsvisning"
+Basic.MainMenu.Edit.Scale="Forhåndsvisning & Skalering"
+Basic.MainMenu.Edit.Scale.Window="Tilpass til vindu"
Basic.MainMenu.Edit.Transform="&Transformer"
Basic.MainMenu.Edit.Transform.EditTransform="&Redigér transformering..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Kopiere transformering"
Basic.MainMenu.Edit.Transform.ResetTransform="&Angre transformering"
Basic.MainMenu.Edit.Transform.Rotate90CW="Rotér 90 grader med klokka"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotér 90 grader mot klokka"
@@ -292,10 +328,21 @@ Basic.MainMenu.Edit.Order.MoveToTop="Legg på &toppen"
Basic.MainMenu.Edit.Order.MoveToBottom="Legg på &bunnen"
Basic.MainMenu.Edit.AdvAudio="&Avanserte lydinstillinger"
+Basic.MainMenu.View="&Vis"
+Basic.MainMenu.View.Toolbars="%Verktøylinje"
+Basic.MainMenu.View.SceneTransitions="Sceneoverganger"
+Basic.MainMenu.View.StatusBar="Statuslinje"
Basic.MainMenu.SceneCollection="&Scenesamling"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Importer Profil"
+Basic.MainMenu.Profile.Export="Eksporter Profil"
+Basic.MainMenu.SceneCollection.Import="Importer Scenesamling"
+Basic.MainMenu.SceneCollection.Export="Eskporter Scenesamling"
+Basic.MainMenu.Profile.Exists="Profilen eksisterer allerede"
+Basic.MainMenu.SceneCollection.Exists="Scenesamlingen eksisterer allerede"
+Basic.MainMenu.Tools="&Verktøy"
Basic.MainMenu.Help="&Hjelp"
Basic.MainMenu.Help.Website="Besøk &nettsted"
@@ -315,6 +362,7 @@ Basic.Settings.General.Theme="Tema"
Basic.Settings.General.Language="Språk"
Basic.Settings.General.WarnBeforeStartingStream="Vis bekreftelsesdialogboks når du starter strømming"
Basic.Settings.General.WarnBeforeStoppingStream="Vis bekreftelsesdialogboks når stanser strømming"
+Basic.Settings.General.Projectors="Projektorer"
Basic.Settings.General.HideProjectorCursor="Skjul musepekeren over projektorer"
Basic.Settings.General.Snapping="Festing ved kildejustering"
Basic.Settings.General.ScreenSnapping="Fest kilder til kanten av skjermen"
@@ -323,6 +371,7 @@ Basic.Settings.General.SourceSnapping="Fest kilder til andre kilder"
Basic.Settings.General.SnapDistance="Festingfølsomhet"
Basic.Settings.General.RecordWhenStreaming="Spill inn automatisk ved strømming"
Basic.Settings.General.KeepRecordingWhenStreamStops="Fortsett innspilling etter strømming"
+Basic.Settings.General.SysTrayWhenStarted="Minimer til systemstatusfelt ved oppstart"
Basic.Settings.Stream="Strøm"
Basic.Settings.Stream.StreamType="Strømmetype"
@@ -337,6 +386,13 @@ Basic.Settings.Output.Mode="Utgangsmodus"
Basic.Settings.Output.Mode.Simple="Enkel"
Basic.Settings.Output.Mode.Adv="Avansert"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg-utgang"
+Basic.Settings.Output.UseReplayBuffer="Aktiver Omspill Buffer"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maksimal Omspill Tid (sekunder)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maksimalt Minne (Megabytes)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Anslått minne bruk. %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Kan ikke beregne minnebruk. Vennligst sett maksimalt minnebrukgrense."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Merk: Sørg for å angi en hurtigtast for omspill bufferen i hurtigtast innstillingen)"
+Basic.Settings.Output.ReplayBuffer.Suffix="Suffiks"
Basic.Settings.Output.Simple.SavePath="Opptaksbane"
Basic.Settings.Output.Simple.RecordingQuality="Opptakskvalitet"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Samme som strøm"
@@ -352,6 +408,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Tapsfri kvalitet advarsel!"
Basic.Settings.Output.Simple.Warn.MultipleQSV="Advarsel: du kan ikke bruke flere separate QSV-kodere når du strømmer og tar opp samtidig. Hvis du ønsker gjøre begge på samme tid må du endre strømme- eller opptakskoderen."
Basic.Settings.Output.Simple.Encoder.Software="Programvare (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Maskinvare (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Maskinvare (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Maskinvare (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Programvare (x264 forhåndsinstilling for liten prosessorbruk, øker filstørrelsen)"
Basic.Settings.Output.VideoBitrate="Bildeoverføringshastighet"
@@ -373,6 +430,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Spor 1"
Basic.Settings.Output.Adv.Audio.Track2="Spor 2"
Basic.Settings.Output.Adv.Audio.Track3="Spor 3"
Basic.Settings.Output.Adv.Audio.Track4="Spor 4"
+Basic.Settings.Output.Adv.Audio.Track5="Spor 5"
+Basic.Settings.Output.Adv.Audio.Track6="Spor 6"
Basic.Settings.Output.Adv.Recording="Opptak"
Basic.Settings.Output.Adv.Recording.Type="Type"
@@ -441,6 +500,11 @@ Basic.Settings.Audio.PushToTalkDelay="Snakk-ved-trykk forsinkelse"
Basic.Settings.Audio.UnknownAudioDevice="[Enhet ikke tilkoblet eller ikke tilgjengelig]"
Basic.Settings.Advanced="Avansert"
+Basic.Settings.Advanced.General.ProcessPriority="Prosessprioritet"
+Basic.Settings.Advanced.General.ProcessPriority.High="Høy"
+Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Over Normal"
+Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal"
+Basic.Settings.Advanced.General.ProcessPriority.Idle="Inaktiv"
Basic.Settings.Advanced.FormatWarning="Advarsel: Fargeformater andre enn NV12 er ment for opptak. Disse formatene anbefales ikke ved strømming, da det fører til økt prosessorbruk som følge av fargeformatkonvertering."
Basic.Settings.Advanced.Audio.BufferingTime="Lydbuffertid"
Basic.Settings.Advanced.Video.ColorFormat="Fargeformat"
@@ -452,6 +516,8 @@ Basic.Settings.Advanced.StreamDelay="Strømforsinkelse"
Basic.Settings.Advanced.StreamDelay.Duration="Varighet (sekunder)"
Basic.Settings.Advanced.StreamDelay.Preserve="Bevar avkuttingspunktet (øk forsinkelse) ved tilbakekobling"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Anslått minnebruk: %1 MB"
+Basic.Settings.Advanced.Network="Nettverk"
+Basic.Settings.Advanced.Network.BindToIP="Bind til IP"
Basic.AdvAudio="Avanserte lydinstillinger"
Basic.AdvAudio.Name="Navn"
@@ -464,13 +530,12 @@ Basic.AdvAudio.AudioTracks="Spor"
Basic.Settings.Hotkeys="Hurtigtaster"
Basic.Settings.Hotkeys.Pair="Tastekombinasjoner delt med '%1' vil veksle"
-Basic.Hotkeys.StartStreaming="Start strømming"
-Basic.Hotkeys.StopStreaming="Stopp strømming"
-Basic.Hotkeys.StartRecording="Start opptak"
-Basic.Hotkeys.StopRecording="Stopp opptak"
Basic.Hotkeys.SelectScene="Bytt til scene"
+Basic.SystemTray.Show="Vis"
+Basic.SystemTray.Hide="Skjul"
+Basic.SystemTray.Message.Reconnecting="Frakoblet. Kobler til på nytt..."
Hotkeys.Insert="Insert"
Hotkeys.Delete="Delete"
diff --git a/UI/data/locale/nl-NL.ini b/UI/data/locale/nl-NL.ini
index 93c31a0..169d48c 100644
--- a/UI/data/locale/nl-NL.ini
+++ b/UI/data/locale/nl-NL.ini
@@ -49,6 +49,26 @@ Right="Rechts"
Top="Boven"
Bottom="Onder"
Reset="Herstellen"
+Hours="Uren"
+Minutes="Minuten"
+Seconds="Seconden"
+Deprecated="Verouderd"
+ReplayBuffer="Replay Buffer"
+Import="Importeer"
+Export="Exporteer"
+
+Updater.Title="Update beschikbaar"
+Updater.Text="Er is een update beschikbaar:"
+Updater.UpdateNow="Nu updaten"
+Updater.RemindMeLater="Herinner mij later"
+Updater.Skip="Sla deze versie over"
+Updater.Running.Title="Programma actief"
+Updater.Running.Text="Er is momenteel uitvoer actief, stop alle actieve uitvoer voor je probeert te updaten"
+Updater.NoUpdatesAvailable.Title="Geen updates beschikbaar"
+Updater.NoUpdatesAvailable.Text="Er zijn momenteel geen updates beschikbaar"
+Updater.FailedToLaunch="Starten van updater is mislukt"
+Updater.GameCaptureActive.Title="Game capture actief"
+Updater.GameCaptureActive.Text="Er is momenteel een game capture hook in gebruik. Sluit alle games/programma's af die opgenomen worden (of herstart Windows) en probeer het opnieuw."
QuickTransitions.SwapScenes="Preview-/uitvoerscenes verwisselen na overgang"
QuickTransitions.SwapScenesTT="Verwisselt de preview- en uitvoercenes na een overgang (als de originele uitvoerscène nog bestaat.)\nDit zal geen veranderingen ongedaan maken die mogelijk zijn gemaakt aan de originele uitvoerscène."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Bevestig het verwijderen"
ConfirmRemove.Text="Weet je zeker dat je '$1' wil verwijderen?"
ConfirmRemove.TextMultiple="Weet je zeker dat je %1 elementen wil verwijderen?"
+Output.StartStreamFailed="Het starten van de stream is mislukt"
+Output.StartRecordingFailed="Het starten van de opname is mislukt"
+Output.StartReplayFailed="Het starten van de replay buffer is mislukt"
+Output.StartFailedGeneric="Het starten van de uitvoer is mislukt. Controleer de logbestanden voor meer informatie.\n\nLet op: Als je gebruik maakt van de NVENC of AMD encoders, controleer of de drivers up to date zijn."
+
Output.ConnectFail.Title="Kan geen verbinding maken"
Output.ConnectFail.BadPath="Ongeldig pad of verbindings-url. Controleer a.u.b. of je instellingen geldig zijn."
Output.ConnectFail.ConnectFailed="Kan geen verbinding maken met de server"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Onvoldoende schijfruimte"
Output.RecordNoSpace.Msg="Er is niet voldoende schijfruimte om door te gaan met opnemen."
Output.RecordError.Title="Opnamefout"
Output.RecordError.Msg="Er is een onbekende fout opgetreden tijdens het opnemen."
+Output.ReplayBuffer.NoHotkey.Title="Er is geen sneltoets ingesteld!"
+Output.ReplayBuffer.NoHotkey.Msg="Er is geen opslaan sneltoets ingesteld voor de replay buffer. Zet aub de \"Opslaan\" sneltoets voor het opslaan van replay-opnames."
Output.BadPath.Title="Ongeldig Bestandspad"
Output.BadPath.Text="Het geconfigureerde bestandsuitvoerpad is ongeldig. Controleer a.u.b. je instellingen om te bevestigen dat er een geldig bestandspad is ingesteld."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Bovenste Veld Eerst"
Deinterlacing.BottomFieldFirst="Onderste Veld Eerst"
+VolControl.SliderUnmuted="Volumeregelaar voor '%1': %2"
+VolControl.SliderMuted="Volumeregelaar voor '%1': %2 (momenteel muted)"
+VolControl.Mute="Mute '%1'"
+VolControl.Properties="Eigenschappen van '%1'"
+
Basic.Main.AddSceneDlg.Title="Scène Toevoegen"
Basic.Main.AddSceneDlg.Text="Voer a.u.b. de naam van de scène in"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Scènes"
Basic.Main.Sources="Bronnen"
Basic.Main.Connecting="Verbinden..."
Basic.Main.StartRecording="Opname Starten"
+Basic.Main.StartReplayBuffer="Start Replay Buffer"
Basic.Main.StartStreaming="Stream Starten"
Basic.Main.StopRecording="Opname Stoppen"
Basic.Main.StoppingRecording="Opname Stoppen..."
+Basic.Main.StopReplayBuffer="Stop Replay Buffer"
+Basic.Main.StoppingReplayBuffer="Replay Buffer aan het stoppen..."
Basic.Main.StopStreaming="Stream Stoppen"
Basic.Main.StoppingStreaming="Stream Stoppen..."
Basic.Main.ForceStopStreaming="Stop Stream (vertraging negeren)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="Opnieuw (&R)"
Basic.MainMenu.Edit.UndoAction="$1 ongedaan maken (&U)"
Basic.MainMenu.Edit.RedoAction="$1 opnieuw toepassen (&R)"
Basic.MainMenu.Edit.LockPreview="Preview vergrende&len"
+Basic.MainMenu.Edit.Scale="Preview &schalen"
+Basic.MainMenu.Edit.Scale.Window="Schaal naar venster"
+Basic.MainMenu.Edit.Scale.Canvas="Canvas (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Uitvoer (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformeren"
Basic.MainMenu.Edit.Transform.EditTransform="Transformatie bewerken... (&E)"
+Basic.MainMenu.Edit.Transform.CopyTransform="Kopieer transformatie"
+Basic.MainMenu.Edit.Transform.PasteTransform="Plak transformatie"
Basic.MainMenu.Edit.Transform.ResetTransform="Transformatie herstellen (&R)"
Basic.MainMenu.Edit.Transform.Rotate90CW="Rechtsom kantelen"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Linksom kantelen"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Statusbalk"
Basic.MainMenu.SceneCollection="&Scèneverzameling"
Basic.MainMenu.Profile="&Profiel"
+Basic.MainMenu.Profile.Import="Importeer profiel"
+Basic.MainMenu.Profile.Export="Exporteer profiel"
+Basic.MainMenu.SceneCollection.Import="Importeer scèneverzameling"
+Basic.MainMenu.SceneCollection.Export="Exporteer scèneverzameling"
+Basic.MainMenu.Profile.Exists="Het profiel bestaat al"
+Basic.MainMenu.SceneCollection.Exists="De scèneverzameling bestaat al"
Basic.MainMenu.Tools="&Tools"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Je hebt onopgeslagen wijzigingen. Wijzigingen opslaan?"
Basic.Settings.General="Algemeen"
Basic.Settings.General.Theme="Thema"
Basic.Settings.General.Language="Taal"
+Basic.Settings.General.EnableAutoUpdates="Automatisch controleren op updates tijdens het opstarten"
Basic.Settings.General.WarnBeforeStartingStream="Laat bevestigingsvenster zien bij het starten van streams"
Basic.Settings.General.WarnBeforeStoppingStream="Laat bevestiginsvenster zien bij het stoppen van streams"
+Basic.Settings.General.Projectors="Projectoren"
Basic.Settings.General.HideProjectorCursor="Verberg cursor boven projectors"
Basic.Settings.General.ProjectorAlwaysOnTop="Houd projectoren altijd bovenaan"
Basic.Settings.General.Snapping="Bronuitlijning"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Bronnen uitlijnen op andere bronnen"
Basic.Settings.General.SnapDistance="Gevoeligheid"
Basic.Settings.General.RecordWhenStreaming="Stream automatisch opnemen"
Basic.Settings.General.KeepRecordingWhenStreamStops="Opname voortzetten als de stream stopt"
-Basic.Settings.General.SysTrayEnabled="Systeemvakicoon weergeven"
+Basic.Settings.General.ReplayBufferWhileStreaming="Replay buffer tegelijk starten met stream"
+Basic.Settings.General.KeepReplayBufferStreamStops="Replay buffer actief houden als stream stopt"
+Basic.Settings.General.SysTray="Systeemvak"
Basic.Settings.General.SysTrayWhenStarted="Naar systeemvak minimaliseren bij opstarten"
+Basic.Settings.General.SystemTrayHideMinimize="Altijd minimaliseren naar het systeemvak in plaats van de taakbalk"
+Basic.Settings.General.SaveProjectors="Projectors opslaan bij afsluiten"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Stream Type"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Uitvoermodus"
Basic.Settings.Output.Mode.Simple="Simpel"
Basic.Settings.Output.Mode.Adv="Geavanceerd"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg-uitvoer"
+Basic.Settings.Output.UseReplayBuffer="Replay Buffer Inschakelen"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximale Replay-tijd (Seconden)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximale hoeveelheid geheugen (Megabytes)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Geschat geheugengebruik: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Kan geheugengebruik niet inschatten. Stel een limiet in op het geheugengebruik."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Let op: Maak een sneltoets voor de replay buffer in de Sneltoetsen sectie)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Replay Buffer Bestandsnaam Prefix"
+Basic.Settings.Output.ReplayBuffer.Suffix="Achtervoegsel"
Basic.Settings.Output.Simple.SavePath="Opnamepad"
Basic.Settings.Output.Simple.RecordingQuality="Opnamekwaliteit"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Hetzelfde als de stream"
@@ -391,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Spoor 1"
Basic.Settings.Output.Adv.Audio.Track2="Spoor 2"
Basic.Settings.Output.Adv.Audio.Track3="Spoor 3"
Basic.Settings.Output.Adv.Audio.Track4="Spoor 4"
+Basic.Settings.Output.Adv.Audio.Track5="Spoor 5"
+Basic.Settings.Output.Adv.Audio.Track6="Spoor 6"
Basic.Settings.Output.Adv.Recording="Opnemen"
Basic.Settings.Output.Adv.Recording.Type="Type"
@@ -471,6 +534,8 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV-Kleurruimte"
Basic.Settings.Advanced.Video.ColorRange="YUV-Kleurbereik"
Basic.Settings.Advanced.Video.ColorRange.Partial="Partial"
Basic.Settings.Advanced.Video.ColorRange.Full="Full"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Audio monitoring apparaat"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Standaard"
Basic.Settings.Advanced.StreamDelay="Streamvertraging"
Basic.Settings.Advanced.StreamDelay.Duration="Duur (seconden)"
Basic.Settings.Advanced.StreamDelay.Preserve="Hervat op het eindpunt (verhoog vertraging) bij opnieuw verbinden"
@@ -484,15 +549,15 @@ Basic.AdvAudio.Volume="Volume (%)"
Basic.AdvAudio.Mono="Downmixen naar Mono"
Basic.AdvAudio.Panning="Pannen"
Basic.AdvAudio.SyncOffset="Sync Offset (ms)"
+Basic.AdvAudio.Monitoring="Audio monitoring"
+Basic.AdvAudio.Monitoring.None="Niet monitoren"
+Basic.AdvAudio.Monitoring.MonitorOnly="Alleen monitoren (uitvoer gedempt)"
+Basic.AdvAudio.Monitoring.Both="Monitoren en uitvoeren"
Basic.AdvAudio.AudioTracks="Sporen"
Basic.Settings.Hotkeys="Sneltoetsen"
Basic.Settings.Hotkeys.Pair="Toetsencombinaties gedeeld met '%1' werken als toggle"
-Basic.Hotkeys.StartStreaming="Stream Starten"
-Basic.Hotkeys.StopStreaming="Stream Stoppen"
-Basic.Hotkeys.StartRecording="Opname Starten"
-Basic.Hotkeys.StopRecording="Opname Stoppen"
Basic.Hotkeys.SelectScene="Wissel naar scène"
Basic.SystemTray.Show="Weergeven"
diff --git a/UI/data/locale/pl-PL.ini b/UI/data/locale/pl-PL.ini
index 14018ad..79eb1ba 100644
--- a/UI/data/locale/pl-PL.ini
+++ b/UI/data/locale/pl-PL.ini
@@ -49,6 +49,26 @@ Right="Od prawej"
Top="Od góry"
Bottom="Od dołu"
Reset="Reset"
+Hours="Godziny"
+Minutes="Minuty"
+Seconds="Sekundy"
+Deprecated="Wycofywane"
+ReplayBuffer="Buffer replayu"
+Import="Importuj"
+Export="Eksportuj"
+
+Updater.Title="Dostępna jest nowa aktualizacja"
+Updater.Text="Dostępna jest nowa aktualizacja:"
+Updater.UpdateNow="Uaktualnij teraz"
+Updater.RemindMeLater="Przypomnij mi później"
+Updater.Skip="Pomiń wersję"
+Updater.Running.Title="Aplikacja jest uruchomiona"
+Updater.Running.Text="Wyjścia są aktualnie aktywne, proszę zamknąć wszystkie aktywne wyjścia przed rozpoczęciem procesu aktualizacji"
+Updater.NoUpdatesAvailable.Title="Brak dostępnych aktualizacji"
+Updater.NoUpdatesAvailable.Text="Brak dostępnych aktualizacji"
+Updater.FailedToLaunch="Nie udało się uruchomić aktualizacji"
+Updater.GameCaptureActive.Title="Przechwytywanie gry aktywne"
+Updater.GameCaptureActive.Text="Przechwytywanie gry jest aktywne. Proszę o zamknięcie wszelkich przechwytywanych gier/aplikacji (lub ponowne uruchomienie systemu) i spróbowanie później."
QuickTransitions.SwapScenes="Zamień podgląd/wyjście scen po przejściu"
QuickTransitions.SwapScenesTT="Zamienia podgląd i wyjście scen po przejściu (jeżeli wyjście oryginalnej sceny istnieje).\nNie przywraca to zmian jakie zostały dokonane w oryginalnej scenie."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Potwierdź usunięcie"
ConfirmRemove.Text="Czy na pewno chcesz usunąć '$1'?"
ConfirmRemove.TextMultiple="Liczba elementów do usunięcia: %1. Czy na pewno chcesz je usunąć?"
+Output.StartStreamFailed="Nie udało się rozpocząć streamowania"
+Output.StartRecordingFailed="Nie udało się rozpocząć nagrywania"
+Output.StartReplayFailed="Nie udało się rozpocząć nagrywania powtórek"
+Output.StartFailedGeneric="Nie udało się uruchomić wyjścia. Sprawdź szczegóły w plikach dziennika.\n\nUwaga: Sprawdź, czy posiadasz aktualne sterowniki karty graficznej, jeżeli używasz enkodera NVENC lub AMD."
+
Output.ConnectFail.Title="Nie udało się połączyć"
Output.ConnectFail.BadPath="Nieprawidłowa ścieżka lub adres URL połączenia. Sprawdź poprawność ustawień."
Output.ConnectFail.ConnectFailed="Nie udało się połączyć z serwerem"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Za mało miejsca na dysku"
Output.RecordNoSpace.Msg="Za mało miejsca na dysku, aby kontynuować nagrywanie."
Output.RecordError.Title="Błąd nagrywania"
Output.RecordError.Msg="Wystąpił nieokreślony błąd podczas nagrywania."
+Output.ReplayBuffer.NoHotkey.Title="Brak klawisza skrótu!"
+Output.ReplayBuffer.NoHotkey.Msg="Klawisz skrótu nie jest zapisany dla buforu replay. Ustaw skrót \"Zapisz\" aby zapisać nagrania replay."
Output.BadPath.Title="Nieprawidłowa ścieżka pliku"
Output.BadPath.Text="Ustawiona ścieżka pliku wynikowego jest nieprawidłowa. Proszę sprawdzić ustawienia."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Najpierw pole górne"
Deinterlacing.BottomFieldFirst="Najpierw pole dolne"
+VolControl.SliderUnmuted="Suwak głośności dla '%1': %2"
+VolControl.SliderMuted="Suwak głośności dla '%1': %2 (obecnie wyciszony)"
+VolControl.Mute="Wycisz '%1'"
+VolControl.Properties="Właściwości dla '%1'"
+
Basic.Main.AddSceneDlg.Title="Dodaj scenę"
Basic.Main.AddSceneDlg.Text="Podaj nazwę sceny"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Sceny"
Basic.Main.Sources="Źródła obrazu"
Basic.Main.Connecting="Łączenie..."
Basic.Main.StartRecording="Rozpocznij nagrywanie"
+Basic.Main.StartReplayBuffer="Rozpocznij bufor replayu"
Basic.Main.StartStreaming="Rozpocznij stream"
Basic.Main.StopRecording="Zatrzymaj nagrywanie"
Basic.Main.StoppingRecording="Zatrzymywanie nagrywania..."
+Basic.Main.StopReplayBuffer="Zatrzymaj bufor replayu"
+Basic.Main.StoppingReplayBuffer="Zatrzymywanie buforu replay..."
Basic.Main.StopStreaming="Zatrzymaj stream"
Basic.Main.StoppingStreaming="Zatrzymywanie streamowania..."
Basic.Main.ForceStopStreaming="Zatrzymaj stream (anuluj opóźnienie)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Wykonaj ponownie"
Basic.MainMenu.Edit.UndoAction="&Cofnij $1"
Basic.MainMenu.Edit.RedoAction="&Wykonaj ponownie $1"
Basic.MainMenu.Edit.LockPreview="Zab&lokuj podgląd"
+Basic.MainMenu.Edit.Scale="&Skalowanie widoku"
+Basic.MainMenu.Edit.Scale.Window="Skaluj do okna"
+Basic.MainMenu.Edit.Scale.Canvas="Powierzchnia robocza (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Powierzchnia wyjściowa (%1x%2)"
Basic.MainMenu.Edit.Transform="&Przekształcanie obrazu"
Basic.MainMenu.Edit.Transform.EditTransform="&Edycja przekształceń..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Skopiuj transformacje"
+Basic.MainMenu.Edit.Transform.PasteTransform="Wklej transformacje"
Basic.MainMenu.Edit.Transform.ResetTransform="&Reset przekształceń"
Basic.MainMenu.Edit.Transform.Rotate90CW="Obróć o 90 stopni zgodnie z ruchem wskazówkek zegara"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Obróć o 90 stopni przeciwnie do ruchu wskazówek zegara"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="Pasek &stanu"
Basic.MainMenu.SceneCollection="Zbiór &scen"
Basic.MainMenu.Profile="P&rofil"
+Basic.MainMenu.Profile.Import="Importuj profil"
+Basic.MainMenu.Profile.Export="Eksportuj profil"
+Basic.MainMenu.SceneCollection.Import="Importuj kolekcje sceny"
+Basic.MainMenu.SceneCollection.Export="Exportuj kolekcje sceny"
+Basic.MainMenu.Profile.Exists="Profil już istnieje"
+Basic.MainMenu.SceneCollection.Exists="Kolekcja sceny już istnieje"
Basic.MainMenu.Tools="&Narzędzia"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Zmiany nie zostały zapisane. Czy zapisać zmiany?"
Basic.Settings.General="Główne"
Basic.Settings.General.Theme="Motyw"
Basic.Settings.General.Language="Język"
+Basic.Settings.General.EnableAutoUpdates="Automatycznie sprawdzaj dostępność aktualizacji"
Basic.Settings.General.WarnBeforeStartingStream="Pokaż komunikat potwierdzenia uruchomienia streamowania"
Basic.Settings.General.WarnBeforeStoppingStream="Pokaż komunikat potwierdzenia zatrzymania streamowania"
+Basic.Settings.General.Projectors="Projektory"
Basic.Settings.General.HideProjectorCursor="Ukryj kursor podglądu na pełnym ekranie"
Basic.Settings.General.ProjectorAlwaysOnTop="Podgląd na pełnym ekranie zawsze na wierzchu"
Basic.Settings.General.Snapping="Przyciąganie elementów źródłowych"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Przyciągaj źródła do innych źródeł
Basic.Settings.General.SnapDistance="Czułość przyciągania"
Basic.Settings.General.RecordWhenStreaming="Automatyczne nagrywanie streamu"
Basic.Settings.General.KeepRecordingWhenStreamStops="Zachowaj nagranie po zatrzymaniu streamu"
-Basic.Settings.General.SysTrayEnabled="Wyświetlaj ikonę w zasobniku systemowym"
+Basic.Settings.General.ReplayBufferWhileStreaming="Automatycznie rozpocznij nagrywanie powtórek w przypadku streamowania"
+Basic.Settings.General.KeepReplayBufferStreamStops="Kontynuuj nagrywanie powtórek po zatrzymaniu streamowania"
+Basic.Settings.General.SysTray="Zasobnik systemowy"
Basic.Settings.General.SysTrayWhenStarted="Minimalizuj do zasobnika systemowego podczas uruchamiania"
+Basic.Settings.General.SystemTrayHideMinimize="Zawsze minimalizuj do zasobnika systemowego zamiast do paska zadań"
+Basic.Settings.General.SaveProjectors="Zapisz konfigurację podglądów na pełnym ekranie przy zamknięciu aplikacji"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Typ streamu"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Tryb wyjścia"
Basic.Settings.Output.Mode.Simple="Proste"
Basic.Settings.Output.Mode.Adv="Zaawansowane"
Basic.Settings.Output.Mode.FFmpeg="Wyjście FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Włącz bufor replay"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maksymalny czas replay (w sekundach)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maksymalna ilość pamięci (w megabajtach)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Szacowane użycie pamięci: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nie można oszacować użycie pamięci. Należy ustawić limit maksymalnej pamięci."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Uwaga: Upewnij się aby ustawić klawisz skrótu dla buforu replay w sekcji Skróty klawiszowe)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Prefiks nazwy pliku buforu replay"
+Basic.Settings.Output.ReplayBuffer.Suffix="Sufiks"
Basic.Settings.Output.Simple.SavePath="Ścieżka pliku"
Basic.Settings.Output.Simple.RecordingQuality="Jakość nagrywania"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Taki sam jak stream"
@@ -391,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Ścieżka 1"
Basic.Settings.Output.Adv.Audio.Track2="Ścieżka 2"
Basic.Settings.Output.Adv.Audio.Track3="Ścieżka 3"
Basic.Settings.Output.Adv.Audio.Track4="Ścieżka 4"
+Basic.Settings.Output.Adv.Audio.Track5="Ścieżka 5"
+Basic.Settings.Output.Adv.Audio.Track6="Ścieżka 6"
Basic.Settings.Output.Adv.Recording="Nagrywanie"
Basic.Settings.Output.Adv.Recording.Type="Typ"
@@ -418,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Ustawienia enkodera video (je
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Enkoder dźwięku"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Ustawienia enkodera audio (jeśli są)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Ustawienia muxera (jeżeli są)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Odstęp między klatkami kluczowymi (klatki)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Pokaż wszystkie kodeki (nawet potencjalnie niezgodne)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -471,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="Przestrzeń kolorów YUV"
Basic.Settings.Advanced.Video.ColorRange="Zakres kolorów YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Częściowy"
Basic.Settings.Advanced.Video.ColorRange.Full="Pełny"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Monitorowane urządzenie audio"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Domyślne"
Basic.Settings.Advanced.StreamDelay="Opóźnienie streamu"
Basic.Settings.Advanced.StreamDelay.Duration="Czas trwania (s)"
Basic.Settings.Advanced.StreamDelay.Preserve="Zachowuj punkt przerwania (zwiększ opóźnienie) podczas ponownego łączenia"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Szacowane zużycie pamięci: %1 MB"
Basic.Settings.Advanced.Network="Sieć"
Basic.Settings.Advanced.Network.BindToIP="Przypisane IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Aktywuj nowy kod sieciowy"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Tryb niskich opóźnień"
Basic.AdvAudio="Zaawansowane ustawienia dźwięku"
Basic.AdvAudio.Name="Nazwa"
@@ -484,15 +553,15 @@ Basic.AdvAudio.Volume="Głośność (%)"
Basic.AdvAudio.Mono="Downmix do Mono"
Basic.AdvAudio.Panning="Rozciągnięcie dźwięku"
Basic.AdvAudio.SyncOffset="Przesunięcie dźwięku (ms)"
+Basic.AdvAudio.Monitoring="Monitorowanie urządzenia audio"
+Basic.AdvAudio.Monitoring.None="Wyłączone"
+Basic.AdvAudio.Monitoring.MonitorOnly="Tylko monitorowanie (wyjście wyłączone)"
+Basic.AdvAudio.Monitoring.Both="Monitorowanie i przekazywanie na wyjście"
Basic.AdvAudio.AudioTracks="Ścieżki"
Basic.Settings.Hotkeys="Skróty klawiszowe"
Basic.Settings.Hotkeys.Pair="Komibnacje klawiszy wspólne z '%1' działają jako przełączniki"
-Basic.Hotkeys.StartStreaming="Rozpocznij stream"
-Basic.Hotkeys.StopStreaming="Zakończ stream"
-Basic.Hotkeys.StartRecording="Rozpocznij nagrywanie"
-Basic.Hotkeys.StopRecording="Zatrzymaj nagrywanie"
Basic.Hotkeys.SelectScene="Przełącz na scenę"
Basic.SystemTray.Show="Pokaż"
@@ -546,4 +615,5 @@ SceneItemHide="Ukryj '%1'"
OutputWarnings.NoTracksSelected="Musisz wybrać przynajmniej jedną ścieżkę"
OutputWarnings.MultiTrackRecording="Ostrzeżenie: Pewne formaty plików (np. FLV) nie obsługują wielu ścieżek dźwiękowych"
+OutputWarnings.MP4Recording="Ostrzeżenie: Nagrania zapisanego w formacie mp4 nie będzie można odzyskać, jeśli plik nie zostanie zakończony poprawnie (np. w wyniku BSOD, braku prądu, itp.). Jeśli chcesz nagrać wiele ścieżek audio należy rozważyć użycie formatu mkv i remux nagrania do mp4 po zakończeniu (Plik -> Przepakuj nagrania)."
diff --git a/UI/data/locale/pt-BR.ini b/UI/data/locale/pt-BR.ini
index 15cf8d3..4fb7cce 100644
--- a/UI/data/locale/pt-BR.ini
+++ b/UI/data/locale/pt-BR.ini
@@ -48,6 +48,14 @@ Left="Esquerda"
Right="Direita"
Top="Topo"
Bottom="Baixo"
+Reset="Redefinir"
+Hours="Horas"
+Minutes="Minutos"
+Seconds="Segundos"
+Deprecated="Obsoleto"
+ReplayBuffer="Buffer do Replay"
+Export="Exportar"
+
QuickTransitions.SwapScenes="Trocar Cenas de Prévia/Saída após a Transição"
QuickTransitions.SwapScenesTT="Troca a preview e a saída após transicionar (se a a cena original de saída ainda exisitr).\nIsto não irá desfazer nenhuma mudança que foi feita na cena original da saída."
@@ -89,6 +97,7 @@ ConfirmRemove.Title="Confirmar a Remoção"
ConfirmRemove.Text="Tem certeza que deseja remover '$1'?"
ConfirmRemove.TextMultiple="Você tem certeza que quer remover esses %1 itens?"
+
Output.ConnectFail.Title="Falha ao conectar"
Output.ConnectFail.BadPath="Caminho inválido ou URL inválida. Por favor verifique se as configurações estão válidas."
Output.ConnectFail.ConnectFailed="Falha ao conectar com o Servidor"
@@ -102,6 +111,8 @@ Output.RecordNoSpace.Title="Espaço em disco insuficiente"
Output.RecordNoSpace.Msg="Não há espaço em disco suficiente para continuar a gravação."
Output.RecordError.Title="Erro de gravação"
Output.RecordError.Msg="Ocorreu um erro não especificado durante a gravação."
+Output.ReplayBuffer.NoHotkey.Title="Tecla de Atalho não configurada!"
+Output.ReplayBuffer.NoHotkey.Msg="Tecla de Atalho para salvar o Buffer do replay não definida. Por favor, configure uma tecla de atalho para salvar gravações de replays."
Output.BadPath.Title="Caminho de Arquivo Inválido"
Output.BadPath.Text="O caminho do arquivo de saída é inválido. Por Favor, certifique-se de que um caminho válido foi informado."
@@ -149,6 +160,7 @@ ScaleFiltering="Filtragem de escala"
ScaleFiltering.Point="Ponto"
ScaleFiltering.Bilinear="Bilinear"
ScaleFiltering.Bicubic="Bicúbico"
+ScaleFiltering.Lanczos="Lanczos"
Deinterlacing="Desentrelaçamento"
Deinterlacing.Discard="Descartar"
@@ -162,6 +174,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Campo Superior Primeiro"
Deinterlacing.BottomFieldFirst="Campo Inferior Primeiro"
+
Basic.Main.AddSceneDlg.Title="Adicionar Cena"
Basic.Main.AddSceneDlg.Text="Por favor, digite o nome da cena"
@@ -256,9 +269,12 @@ Basic.Main.Scenes="Cenas"
Basic.Main.Sources="Fontes"
Basic.Main.Connecting="Conectando..."
Basic.Main.StartRecording="Iniciar gravação"
+Basic.Main.StartReplayBuffer="Iniciar Buffer do Replay"
Basic.Main.StartStreaming="Iniciar Transmissão"
Basic.Main.StopRecording="Parar Gravação"
Basic.Main.StoppingRecording="Parando de Gravar..."
+Basic.Main.StopReplayBuffer="Parar Buffer do Replay"
+Basic.Main.StoppingReplayBuffer="Parando Buffer do Replay..."
Basic.Main.StopStreaming="Parar Transmissão"
Basic.Main.StoppingStreaming="Parando Transmissão..."
Basic.Main.ForceStopStreaming="Pare de transmitir (descartar atraso)"
@@ -280,8 +296,14 @@ Basic.MainMenu.Edit.Redo="&Refazer"
Basic.MainMenu.Edit.UndoAction="&Desfazer $1"
Basic.MainMenu.Edit.RedoAction="&Refazer $1"
Basic.MainMenu.Edit.LockPreview="&Bloquear pré-visualização"
+Basic.MainMenu.Edit.Scale="Visualização e dimensionamento"
+Basic.MainMenu.Edit.Scale.Window="Escala para janela"
+Basic.MainMenu.Edit.Scale.Canvas="Lona (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Saída (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformar"
Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformação..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Copiar Transformação"
+Basic.MainMenu.Edit.Transform.PasteTransform="Colar Transformação"
Basic.MainMenu.Edit.Transform.ResetTransform="&Limpar Transformação"
Basic.MainMenu.Edit.Transform.Rotate90CW="Girar 90º sentido Horário"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Girar 90º sentido Anti-Horário"
@@ -306,6 +328,12 @@ Basic.MainMenu.View.StatusBar="Barra de Status"
Basic.MainMenu.SceneCollection="&Coleção de cena"
Basic.MainMenu.Profile="&Perfil"
+Basic.MainMenu.Profile.Import="Importar Perfil"
+Basic.MainMenu.Profile.Export="Exportar Perfil"
+Basic.MainMenu.SceneCollection.Import="Importar Grupo de Cenas"
+Basic.MainMenu.SceneCollection.Export="Exportar Grupo de Cenas"
+Basic.MainMenu.Profile.Exists="Perfil já existe"
+Basic.MainMenu.SceneCollection.Exists="O Grupo de Cenas já existe"
Basic.MainMenu.Tools="Ferramentas (&T)"
@@ -336,8 +364,8 @@ Basic.Settings.General.SourceSnapping="Encaixar fontes com outras fontes"
Basic.Settings.General.SnapDistance="Sensibilidade de Encaixamento"
Basic.Settings.General.RecordWhenStreaming="Gravar automaticamente quando estiver transmitindo"
Basic.Settings.General.KeepRecordingWhenStreamStops="Continuar gravando quando a transmissão parar"
-Basic.Settings.General.SysTrayEnabled="Habilitar o ícone de bandeja do sistema"
Basic.Settings.General.SysTrayWhenStarted="Minimizar para a bandeja do sistema quando iniciar"
+Basic.Settings.General.SaveProjectors="Salvar projetores ao sair"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Tipo de Stream"
@@ -352,6 +380,14 @@ Basic.Settings.Output.Mode="Modo de Saída"
Basic.Settings.Output.Mode.Simple="Simples"
Basic.Settings.Output.Mode.Adv="Avançado"
Basic.Settings.Output.Mode.FFmpeg="Saída de FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Habilitar Buffer de Repetição"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Tempo de Replay máximo (Segundos)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Memória Máxima (Megabytes)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Uso de memória estimado: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Impossível estimar o uso de memória. Por favor, defina o limite máximo de memória."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Nota: Não se esqueça de configurar uma Tecla de Atalho para o Buffer de Replay na seção Teclas de Atalhos)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Prefixo do Buffer de Repetição"
+Basic.Settings.Output.ReplayBuffer.Suffix="Sufixo"
Basic.Settings.Output.Simple.SavePath="Caminho de gravação"
Basic.Settings.Output.Simple.RecordingQuality="Qualidade da gravação"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Mesmo que a stream"
@@ -367,6 +403,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Aviso de qualidade lossless!"
Basic.Settings.Output.Simple.Warn.MultipleQSV="Aviso: Você não pode usar vários codificadores QSV separados quando estiver transmitindo e gravando ao mesmo tempo. Se você deseja transmitir e gravar ao mesmo tempo, por favor altere o codificador de gravação ou o de transmissão."
Basic.Settings.Output.Simple.Encoder.Software="Software (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hardware (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hardware (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hardware (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (preset x264 de baixa utilização de CPU, aumenta o tamanho do arquivo)"
Basic.Settings.Output.VideoBitrate="Taxa de Bits do Vídeo"
@@ -388,6 +425,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Faixa 1"
Basic.Settings.Output.Adv.Audio.Track2="Faixa 2"
Basic.Settings.Output.Adv.Audio.Track3="Faixa 3"
Basic.Settings.Output.Adv.Audio.Track4="Faixa 4"
+Basic.Settings.Output.Adv.Audio.Track5="Faixa 5"
+Basic.Settings.Output.Adv.Audio.Track6="Faixa 6"
Basic.Settings.Output.Adv.Recording="Gravação"
Basic.Settings.Output.Adv.Recording.Type="Tipo"
@@ -416,7 +455,7 @@ Basic.Settings.Output.Adv.FFmpeg.AEncoder="Codificador de áudio"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Configurações do codificador de áudio(se houver)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Configurações do Muxer (se houver)"
-FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
+FilenameFormatting.completer="%CCYY-% MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %H-%M-%S\n%A %d-%Y-%m %Y-%m-%d %H-%M-%S\n%Y-%b-123_2_ 16_321 %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H %M - %S-%Z"
FilenameFormatting.TT="%CCYY Ano, quatro dígitos\n%YY Ano, dois dígitos (00-99)\n%MM Mês como um número decimal (01-12)\n%DD Dia do mês, começando com 0 (01-31)\n%hh Hora, em formato de 24h (00-23)\n%mm Minuto (00-59)\n%ss Segundo (00-61)\n%% A % sign\n%a Dia da Semana abreviado\n%A Nome da Semana completo\n%b Nome do Mês abreviado\n%B Nome do Mês completo\n%d Dia do Mês, começando com 0 (01-31)\n%H Hora, no formato de 24h (00-23)\n%I Hora no formato de 12h (01-12)\n%m Mês como um número decimal (01-12)\n%M Minuto (00-59)\n%p Designação AM ou PM\n%S Segundo (00-61)\n%y Ano, últimos dois dígitos (00-99)\n%Y Ano\n%z ISO 8601 diferença de fuso horário ou de UTC\n nome ou abreviação\n%Z Nome do Fuso Horário ou abreviação\n"
@@ -468,6 +507,7 @@ Basic.Settings.Advanced.Video.ColorSpace="Espaço de cor YUV"
Basic.Settings.Advanced.Video.ColorRange="Gama de cores YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Limitado"
Basic.Settings.Advanced.Video.ColorRange.Full="Completo"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Padrão"
Basic.Settings.Advanced.StreamDelay="Atraso da transmissão"
Basic.Settings.Advanced.StreamDelay.Duration="Duração (segundos)"
Basic.Settings.Advanced.StreamDelay.Preserve="Preservar o ponto de corte (aumento de atraso) quando reconectar"
@@ -486,10 +526,6 @@ Basic.AdvAudio.AudioTracks="Faixas"
Basic.Settings.Hotkeys="Teclas de atalho"
Basic.Settings.Hotkeys.Pair="Combinações de teclas compartilhadas com '%1' agem como alternaçoes"
-Basic.Hotkeys.StartStreaming="Iniciar transmissão"
-Basic.Hotkeys.StopStreaming="Parar transmissão"
-Basic.Hotkeys.StartRecording="Iniciar gravação"
-Basic.Hotkeys.StopRecording="Parar gravação"
Basic.Hotkeys.SelectScene="Mudar de cena"
Basic.SystemTray.Show="Exibir"
diff --git a/UI/data/locale/pt-PT.ini b/UI/data/locale/pt-PT.ini
index 6edac0a..24feb7d 100644
--- a/UI/data/locale/pt-PT.ini
+++ b/UI/data/locale/pt-PT.ini
@@ -48,6 +48,11 @@ Left="Esquerda"
Right="Direita"
Top="Cima"
Bottom="Baixo"
+Reset="Repor"
+Hours="Horas"
+Minutes="Minutos"
+Seconds="Segundos"
+
QuickTransitions.SwapScenes="Trocar pré-visualização/saída de cenas Depois de uma Transição"
QuickTransitions.DuplicateScene="Duplicar cena"
@@ -85,6 +90,8 @@ ConfirmExit.Text="O OBS está ligado. Todas as transmissões e gravações serã
ConfirmRemove.Title="Comfirmar Remover"
ConfirmRemove.Text="Tem a certeza que quer remover '$1'?"
+ConfirmRemove.TextMultiple="Tem a certeza de que pretende remover %1 itens?"
+
Output.ConnectFail.Title="Falha ao ligar"
Output.ConnectFail.BadPath="Caminho ou endereço de ligação inválido. Por favor, verifique as suas definições para confirmar que são válidas."
@@ -155,6 +162,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Campo Superior Primeiro"
Deinterlacing.BottomFieldFirst="Campo Inferior Primeiro"
+
Basic.Main.AddSceneDlg.Title="Adicionar Cena"
Basic.Main.AddSceneDlg.Text="Por favor introduza o nome da cena"
@@ -185,7 +193,9 @@ Basic.PropertiesWindow.ConfirmTitle="Definições alteradas"
Basic.PropertiesWindow.Confirm="Há alterações não guardadas. Pretende mantê-las?"
Basic.PropertiesWindow.NoProperties="Sem propriedades disponíveis"
Basic.PropertiesWindow.AddFiles="Adicionar ficheiros"
+Basic.PropertiesWindow.AddDir="Adicionar diretório"
Basic.PropertiesWindow.AddURL="Adicionar caminho ou endereço"
+Basic.PropertiesWindow.AddEditableListDir="Adicionar diretório a '%1'"
Basic.PropertiesWindow.AddEditableListFiles="Adicionar ficheiros a '%1'"
Basic.PropertiesWindow.AddEditableListEntry="Adicionar entrada a '%1'"
Basic.PropertiesWindow.EditEditableListEntry="Editar entrada a '%1'"
@@ -249,7 +259,9 @@ Basic.Main.Connecting="A ligar..."
Basic.Main.StartRecording="Começar Gravação"
Basic.Main.StartStreaming="Iniciar transmissão"
Basic.Main.StopRecording="Parar Gravação"
+Basic.Main.StoppingRecording="A parar gravação..."
Basic.Main.StopStreaming="Parar transmissão"
+Basic.Main.StoppingStreaming="A parar transmissão..."
Basic.Main.ForceStopStreaming="Parar transmissão (ignorar atraso)"
Basic.MainMenu.File="&Ficheiro"
@@ -268,6 +280,7 @@ Basic.MainMenu.Edit.Undo="Desfazer"
Basic.MainMenu.Edit.Redo="&Refazer"
Basic.MainMenu.Edit.UndoAction="Desfazer $1"
Basic.MainMenu.Edit.RedoAction="&Refazer $1"
+Basic.MainMenu.Edit.LockPreview="B&loquear pré-visualização"
Basic.MainMenu.Edit.Transform="&Transformar"
Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformação..."
Basic.MainMenu.Edit.Transform.ResetTransform="&Reset Transform"
@@ -286,10 +299,15 @@ Basic.MainMenu.Edit.Order.MoveToTop="Mover para p &Topo"
Basic.MainMenu.Edit.Order.MoveToBottom="Mover para o Fundo"
Basic.MainMenu.Edit.AdvAudio="Propriedades &avançadas de áudio"
+Basic.MainMenu.View="&Ver"
+Basic.MainMenu.View.Toolbars="Barras de ferramen&tas"
+Basic.MainMenu.View.SceneTransitions="Transições de &cenas"
+Basic.MainMenu.View.StatusBar="&Barra de estado"
Basic.MainMenu.SceneCollection="Coleção de cena"
Basic.MainMenu.Profile="&Perfil"
+Basic.MainMenu.Tools="&Ferramentas"
Basic.MainMenu.Help="&Ajuda"
Basic.MainMenu.Help.Website="Visitar &website"
@@ -311,6 +329,9 @@ Basic.Settings.General.WarnBeforeStartingStream="Mostrar caixa de diálogo de co
Basic.Settings.General.WarnBeforeStoppingStream="Mostrar caixa de diálogo de confirmação ao parar transmissões"
Basic.Settings.General.Snapping="Alinhamentos com encaixe na Cena"
Basic.Settings.General.SnapDistance="Sensibilidade do Snap"
+Basic.Settings.General.RecordWhenStreaming="Gravar automaticamente quando estiver a transmitir"
+Basic.Settings.General.KeepRecordingWhenStreamStops="Continuar a gravar quando a transmissão parar"
+Basic.Settings.General.SysTrayWhenStarted="Minimizar para a área de notificações quando iniciado"
Basic.Settings.Stream="Transmissão"
Basic.Settings.Stream.StreamType="Tipo de transmissão"
@@ -423,6 +444,11 @@ Basic.Settings.Audio.PushToTalkDelay="Atraso do push-to-talk"
Basic.Settings.Audio.UnknownAudioDevice="[Dispositivo não conectado ou não disponível]"
Basic.Settings.Advanced="Avançado"
+Basic.Settings.Advanced.General.ProcessPriority="Prioridade do precesso"
+Basic.Settings.Advanced.General.ProcessPriority.High="Alta"
+Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Acima do normal"
+Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal"
+Basic.Settings.Advanced.General.ProcessPriority.Idle="Inativo"
Basic.Settings.Advanced.FormatWarning="Aviso: Formatos de cor diferentes de NV12 destinam-se principalmente a gravação e não são recomendados durante a transmissão. A transmissão pode incorrer numa maior utilização do processador devido à conversão do formato de cor."
Basic.Settings.Advanced.Audio.BufferingTime="Tempo de carregamento do áudio"
Basic.Settings.Advanced.Video.ColorFormat="Formato de cor"
@@ -434,6 +460,8 @@ Basic.Settings.Advanced.StreamDelay="Atraso na trasmissão"
Basic.Settings.Advanced.StreamDelay.Duration="Duração (segundos)"
Basic.Settings.Advanced.StreamDelay.Preserve="Preservar o ponto de corte (aumentar atraso) quando reconectar"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Utilização estimada de memória: %1 MB"
+Basic.Settings.Advanced.Network="Rede"
+Basic.Settings.Advanced.Network.BindToIP="Ligar pelo IP"
Basic.AdvAudio="Propriedades avançadas de áudio"
Basic.AdvAudio.Name="Nome"
@@ -446,13 +474,12 @@ Basic.AdvAudio.AudioTracks="Faixas"
Basic.Settings.Hotkeys="Teclas de atalho"
Basic.Settings.Hotkeys.Pair="Combinações de teclas partilhadas com '%1' atuam como alavancas"
-Basic.Hotkeys.StartStreaming="Iniciar transmissão"
-Basic.Hotkeys.StopStreaming="Parar transmissão"
-Basic.Hotkeys.StartRecording="Iniciar gravação"
-Basic.Hotkeys.StopRecording="Parar gravação"
Basic.Hotkeys.SelectScene="Mudar para cena"
+Basic.SystemTray.Show="Mostrar"
+Basic.SystemTray.Hide="Ocultar"
+Basic.SystemTray.Message.Reconnecting="Desligado. A religar..."
Hotkeys.Insert="Insert"
Hotkeys.Delete="Delete"
diff --git a/UI/data/locale/ro-RO.ini b/UI/data/locale/ro-RO.ini
index e58bc14..d39fc9b 100644
--- a/UI/data/locale/ro-RO.ini
+++ b/UI/data/locale/ro-RO.ini
@@ -48,6 +48,13 @@ Left="Stânga"
Right="Dreapta"
Top="Sus"
Bottom="Jos"
+Hours="Ore"
+Minutes="Minute"
+Seconds="Secunde"
+Deprecated="Invechit"
+Import="Importă"
+Export="Exportă"
+
QuickTransitions.SwapScenes="Comută între previzualizare/scenele de ieșire după tranziționare"
QuickTransitions.SwapScenesTT="Schimba previzualizarea si scenele de output dupa tranzitionare (în cazul în care încă există outputul scenei originale). \nAceasta nu va anula nicio modificăre care au fost făcute la outputul scenei originale."
@@ -87,6 +94,8 @@ ConfirmExit.Text="OBS este în prezent activ. Toate streamurile/înregistrăril
ConfirmRemove.Title="Confirmă eliminarea"
ConfirmRemove.Text="Sigur dorești să elimini „$1”?"
+ConfirmRemove.TextMultiple="Sigur doriți sa eliminați %1 obiecte?"
+
Output.ConnectFail.Title="Eșec la conectare"
Output.ConnectFail.BadPath="URL-ul conexiunii sau calea este invalidă. Te rugăm să verifici setările pentru a confirma că acestea sunt valide."
@@ -118,6 +127,7 @@ LicenseAgreement.Exit="Ieși"
Remux.SourceFile="Înregistrare OBS"
Remux.TargetFile="Fișier țintă"
Remux.Remux="Remux"
+Remux.OBSRecording="Înregistrare OBS"
Remux.FinishedTitle="Remuxing încheiat"
Remux.Finished="Înregistrare remuxată"
Remux.FinishedError="Înregistrare remuxată, însă fișierul poate fi incomplet"
@@ -143,6 +153,9 @@ Basic.DisplayCapture="Captură de display"
Basic.Main.PreviewConextMenu.Enable="Activează previzualizarea"
+ScaleFiltering.Bilinear="Biliniar"
+ScaleFiltering.Bicubic="Bicubic"
+ScaleFiltering.Lanczos="Lanczos"
Deinterlacing="Deîntrețesere"
Deinterlacing.Discard="Înlătură"
@@ -156,6 +169,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Câmpul de sus prima oară"
Deinterlacing.BottomFieldFirst="Câmpul de jos prima oară"
+
Basic.Main.AddSceneDlg.Title="Adaugă scenă"
Basic.Main.AddSceneDlg.Text="Te rugăm să introduci numele scenei"
@@ -290,7 +304,11 @@ Basic.MainMenu.Edit.AdvAudio="Proprietăți audio &avansate"
Basic.MainMenu.SceneCollection="Colecție de &scene"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Importă Profil"
+Basic.MainMenu.Profile.Export="Exportă profil"
+Basic.MainMenu.Profile.Exists="Profilul deja există"
+Basic.MainMenu.Tools="&Unelte"
Basic.MainMenu.Help="&Ajutor"
Basic.MainMenu.Help.Website="Vizitează site-ul &web"
@@ -329,6 +347,8 @@ Basic.Settings.Output.Mode="Mod de ieșire"
Basic.Settings.Output.Mode.Simple="Simplu"
Basic.Settings.Output.Mode.Adv="Avansat"
Basic.Settings.Output.Mode.FFmpeg="Ieșire FFmpeg"
+Basic.Settings.Output.ReplayBuffer.Estimate="Utilizare estimată a memoriei: %1 MB"
+Basic.Settings.Output.ReplayBuffer.Suffix="Sufix"
Basic.Settings.Output.Simple.SavePath="Cale de înregistrare"
Basic.Settings.Output.Simple.RecordingQuality="Calitatea înregistrării"
Basic.Settings.Output.Simple.RecordingQuality.Stream="La fel cu cea a streamului"
@@ -432,6 +452,11 @@ Basic.Settings.Audio.PushToTalkDelay="Întârziere push-to-talk"
Basic.Settings.Audio.UnknownAudioDevice="[Dispozitivul nu este disponibil sau nu este conectat]"
Basic.Settings.Advanced="Avansate"
+Basic.Settings.Advanced.General.ProcessPriority="Prioritate Proces"
+Basic.Settings.Advanced.General.ProcessPriority.High="Ridicată"
+Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Peste Normal"
+Basic.Settings.Advanced.General.ProcessPriority.Normal="Normală"
+Basic.Settings.Advanced.General.ProcessPriority.Idle="Inactiv"
Basic.Settings.Advanced.FormatWarning="Atentie: Formatele de culori diferite de NV12 sunt facute pentru inregistrare si nu sunt recomandate in cazul streaming-ului. Streaming-ul e posibil sa ceara mai multe resurse CPU datorita conversiei formatului culorii."
Basic.Settings.Advanced.Audio.BufferingTime="Timp de buffering pentru audio"
Basic.Settings.Advanced.Video.ColorFormat="Format de culoare"
@@ -443,6 +468,8 @@ Basic.Settings.Advanced.StreamDelay="Întârziere pentru stream"
Basic.Settings.Advanced.StreamDelay.Duration="Durată (secunde)"
Basic.Settings.Advanced.StreamDelay.Preserve="Păstrează punctul de tăiere (crește întârzierea) la reconectare"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Utilizare estimată a memoriei: %1 MB"
+Basic.Settings.Advanced.Network="Rețea"
+Basic.Settings.Advanced.Network.BindToIP="Leagă de IP"
Basic.AdvAudio="Proprietăți audio avansate"
Basic.AdvAudio.Name="Nume"
@@ -455,13 +482,12 @@ Basic.AdvAudio.AudioTracks="Piste"
Basic.Settings.Hotkeys="Taste rapide"
Basic.Settings.Hotkeys.Pair="Combinațiile de taste partajate cu '%1' acționează ca comutatoare"
-Basic.Hotkeys.StartStreaming="Pornește streamingul"
-Basic.Hotkeys.StopStreaming="Oprește streamingul"
-Basic.Hotkeys.StartRecording="Pornește înregistrarea"
-Basic.Hotkeys.StopRecording="Oprește înregistrarea"
Basic.Hotkeys.SelectScene="Comută la scenă"
+Basic.SystemTray.Show="Afișează"
+Basic.SystemTray.Hide="Ascunde"
+Basic.SystemTray.Message.Reconnecting="Deconectat. Reconectare..."
Hotkeys.Insert="Inserează"
Hotkeys.Delete="Șterge"
diff --git a/UI/data/locale/ru-RU.ini b/UI/data/locale/ru-RU.ini
index b170c8b..2a184b1 100644
--- a/UI/data/locale/ru-RU.ini
+++ b/UI/data/locale/ru-RU.ini
@@ -49,6 +49,26 @@ Right="Справа"
Top="Сверху"
Bottom="Снизу"
Reset="Сбросить"
+Hours="Часов"
+Minutes="Минут"
+Seconds="Секунд"
+Deprecated="Устаревшее"
+ReplayBuffer="Буфер повтора"
+Import="Импорт"
+Export="Экспорт"
+
+Updater.Title="Доступно обновление"
+Updater.Text="Доступно новое обновление:"
+Updater.UpdateNow="Обновить сейчас"
+Updater.RemindMeLater="Напомнить позже"
+Updater.Skip="Пропустить версию"
+Updater.Running.Title="Программа в настоящее время активна"
+Updater.Running.Text="Обнаружена активная операция вывода. Перед обновлением необходимо отключить все активные операции вывода"
+Updater.NoUpdatesAvailable.Title="Нет доступных обновлений"
+Updater.NoUpdatesAvailable.Text="Обновления не обнаружены"
+Updater.FailedToLaunch="Не удалось проверить обновления"
+Updater.GameCaptureActive.Title="Производится захват игры"
+Updater.GameCaptureActive.Text="Библиотека захвата игр уже используется. Закройте захватываемые игры/программы (или перезапустите Windows) и попробуйте ещё раз."
QuickTransitions.SwapScenes="Замена Просмотра/Вывода Сцены После Перехода"
QuickTransitions.SwapScenesTT="Замена просмотра и вывода сцены после перехода (если выходная оригинальная сцена до сих пор существует).\nЭто будет не отмена каких-либо изменений, что, возможно, было сделано в выходной оригинальной сцены."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Подтвердить удаление"
ConfirmRemove.Text="Вы уверены, что хотите удалить '$1'?"
ConfirmRemove.TextMultiple="Вы уверены, что вы хотите удалить %1 элементов?"
+Output.StartStreamFailed="Не удалось запустить вещание"
+Output.StartRecordingFailed="Не удалось начать запись"
+Output.StartReplayFailed="Не удалось запустить воспроизведение из буфера"
+Output.StartFailedGeneric="Сбой вывода. Подробности отражены в журнале.\n\nПримечание: Если вы используете кодировщики NVENC или AMD, убедитесь что у вас установлена последняя версия видеорайвера."
+
Output.ConnectFail.Title="Не удалось подключиться"
Output.ConnectFail.BadPath="Неверный путь или URL соединения. Пожалуйста, проверьте настройки, чтобы подтвердить, что они являются действительными."
Output.ConnectFail.ConnectFailed="Не удалось подключиться к серверу"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Недостаточно места на диске"
Output.RecordNoSpace.Msg="На диске недостаточно места для продолжения записи."
Output.RecordError.Title="Ошибка записи"
Output.RecordError.Msg="Во время записи произошла неопознанная ошибка."
+Output.ReplayBuffer.NoHotkey.Title="Нет набора горячих клавиш!"
+Output.ReplayBuffer.NoHotkey.Msg="Не установлено клавиши для сохранения повтора. Пожалуйста, установите горячую клавишу для сохранения записей повторов."
Output.BadPath.Title="Неправильный путь к файлу"
Output.BadPath.Text="Некорректный путь к файлу. Пожалуйста, проверьте настройки, чтобы убедиться в корректности установленного пути."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Верхнее поле первое"
Deinterlacing.BottomFieldFirst="Нижнее поле первое"
+VolControl.SliderUnmuted="Регулятор громкости '%1': %2"
+VolControl.SliderMuted="Регулятор громкости '%1': %2 (сейчас заглушен)"
+VolControl.Mute="Заглушить '%1'"
+VolControl.Properties="Свойства '%1'"
+
Basic.Main.AddSceneDlg.Title="Добавить сцену"
Basic.Main.AddSceneDlg.Text="Пожалуйста, введите название сцены"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Сцены"
Basic.Main.Sources="Источники"
Basic.Main.Connecting="Соединение..."
Basic.Main.StartRecording="Начать запись"
+Basic.Main.StartReplayBuffer="Запустить повтор"
Basic.Main.StartStreaming="Запустить трансляцию"
Basic.Main.StopRecording="Остановить запись"
Basic.Main.StoppingRecording="Остановка Записи..."
+Basic.Main.StopReplayBuffer="Остановить повтор"
+Basic.Main.StoppingReplayBuffer="Остановка повтора..."
Basic.Main.StopStreaming="Остановить трансляцию"
Basic.Main.StoppingStreaming="Остановка вещания..."
Basic.Main.ForceStopStreaming="Остановить передачу (отменить задержку)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Повторить"
Basic.MainMenu.Edit.UndoAction="&Отменить $1"
Basic.MainMenu.Edit.RedoAction="&Повторить $1"
Basic.MainMenu.Edit.LockPreview="&Заблокировать предпросмотр"
+Basic.MainMenu.Edit.Scale="Просмотр и масштабирование"
+Basic.MainMenu.Edit.Scale.Window="Масштаб окна"
+Basic.MainMenu.Edit.Scale.Canvas="Холст (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Вывод (%1x%2)"
Basic.MainMenu.Edit.Transform="&Преобразовать"
Basic.MainMenu.Edit.Transform.EditTransform="&Изменить преобразование..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Копировать преобразование"
+Basic.MainMenu.Edit.Transform.PasteTransform="Вставить преобразование"
Basic.MainMenu.Edit.Transform.ResetTransform="&Сбросить преобразование"
Basic.MainMenu.Edit.Transform.Rotate90CW="Повернуть на 90 градусов по часовой"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Повернуть на 90 градусов против часовой"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Строка состояния"
Basic.MainMenu.SceneCollection="Коллекция сцен"
Basic.MainMenu.Profile="Профиль"
+Basic.MainMenu.Profile.Import="Импортировать профиль"
+Basic.MainMenu.Profile.Export="Экспортировать профиль"
+Basic.MainMenu.SceneCollection.Import="Импортировать коллекцию сцен"
+Basic.MainMenu.SceneCollection.Export="Экспортировать коллекцию сцен"
+Basic.MainMenu.Profile.Exists="Профиль уже существует"
+Basic.MainMenu.SceneCollection.Exists="Коллекция сцен уже существует"
Basic.MainMenu.Tools="&Инструменты"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="У вас есть несохраненные измен
Basic.Settings.General="Общие"
Basic.Settings.General.Theme="Тема"
Basic.Settings.General.Language="Язык"
+Basic.Settings.General.EnableAutoUpdates="Проверять наличие обновлений при запуске"
Basic.Settings.General.WarnBeforeStartingStream="Показывать окно подтверждения при запуске трансляции"
Basic.Settings.General.WarnBeforeStoppingStream="Показывать окно подтверждения при остановке трансляции"
+Basic.Settings.General.Projectors="Проекторы"
Basic.Settings.General.HideProjectorCursor="Скрыть курсор за проекторы"
Basic.Settings.General.ProjectorAlwaysOnTop="Показывать проекторы поверх всего остального"
Basic.Settings.General.Snapping="Привязка расположения источника"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Привязка к другим исто
Basic.Settings.General.SnapDistance="Чувствительность привязки"
Basic.Settings.General.RecordWhenStreaming="Автоматическая запись при стриме"
Basic.Settings.General.KeepRecordingWhenStreamStops="Продолжить запись, когда стрим остановится"
-Basic.Settings.General.SysTrayEnabled="Показывать иконку в системном трее"
+Basic.Settings.General.ReplayBufferWhileStreaming="Автоматически запускать буфер повтора во время трансляции"
+Basic.Settings.General.KeepReplayBufferStreamStops="Сохранять буфер повтора активным когда останавливается трансляция"
+Basic.Settings.General.SysTray="Системный трей"
Basic.Settings.General.SysTrayWhenStarted="Скрывать окно в системный трей при запуске"
+Basic.Settings.General.SystemTrayHideMinimize="Всегда сворачивать в трей вместо панели задач"
+Basic.Settings.General.SaveProjectors="Сохранять проекторы при выходе"
Basic.Settings.Stream="Вещание"
Basic.Settings.Stream.StreamType="Тип вещания"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Режим вывода"
Basic.Settings.Output.Mode.Simple="Простой"
Basic.Settings.Output.Mode.Adv="Расширенные"
Basic.Settings.Output.Mode.FFmpeg="Вывод FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Включить Буфер повтора"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Максимальное время повтора (секунд)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Максимальный объем памяти (МБ)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Предполагаемое использование памяти: %1 МБ"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Невозможно оценить использование памяти. Пожалуйста, установите максимальный объем памяти."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Примечание: Убедитесь, что установили горячую клавишу для воспроизведения буфера в разделе горячие клавиши)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Префикс имени файла повтора"
+Basic.Settings.Output.ReplayBuffer.Suffix="Суффикс"
Basic.Settings.Output.Simple.SavePath="Путь к записи"
Basic.Settings.Output.Simple.RecordingQuality="Качество записи"
Basic.Settings.Output.Simple.RecordingQuality.Stream="То же, что у трансляции"
@@ -391,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Дорожка 1"
Basic.Settings.Output.Adv.Audio.Track2="Дорожка 2"
Basic.Settings.Output.Adv.Audio.Track3="Дорожка 3"
Basic.Settings.Output.Adv.Audio.Track4="Дорожка 4"
+Basic.Settings.Output.Adv.Audio.Track5="Дорожка 5"
+Basic.Settings.Output.Adv.Audio.Track6="Дорожка 6"
Basic.Settings.Output.Adv.Recording="Запись"
Basic.Settings.Output.Adv.Recording.Type="Тип"
@@ -418,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Настройки кодир
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Кодировщик аудио"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Настройки кодировщика аудио (если есть)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Настройки мультиплексора (если есть)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Интервал ключевых кадров (кадры)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Показать все кодеки (даже потенциально несовместимые)"
FilenameFormatting.completer="%DD-%MM-%CCYY %hh-%mm-%ss\n%DD-%MM-%YY %hh-%mm-%ss\n%d-%m-%Y %H-%M-%S\n%d-%m-%y %H-%M-%S\n%a %d-%m-%Y %H-%M-%S\n%A %d-%m-%Y %H-%M-%S\n%d-%b-%Y %H-%M-%S\n%d-%B-%Y %H-%M-%S"
@@ -471,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="Цветовое пространст
Basic.Settings.Advanced.Video.ColorRange="Цветовой диапазон YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Частичный"
Basic.Settings.Advanced.Video.ColorRange.Full="Полный"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Устройство прослушивания аудио"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="По умолчанию"
Basic.Settings.Advanced.StreamDelay="Задержка потока"
Basic.Settings.Advanced.StreamDelay.Duration="Продолжительность (секунд)"
Basic.Settings.Advanced.StreamDelay.Preserve="Сохранить точку отсечки (увеличить задержку) при переподключении"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Предполагаемое использование памяти: %1 МБ"
Basic.Settings.Advanced.Network="Сеть"
Basic.Settings.Advanced.Network.BindToIP="Привязать к IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Включить новый сетевой код"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Режим низкой задержки"
Basic.AdvAudio="Расширенные свойства аудио"
Basic.AdvAudio.Name="Название"
@@ -484,15 +553,15 @@ Basic.AdvAudio.Volume="Громкость (%)"
Basic.AdvAudio.Mono="Объединение в один канал"
Basic.AdvAudio.Panning="Панорамирование"
Basic.AdvAudio.SyncOffset="Смещение синхронизации (мс)"
+Basic.AdvAudio.Monitoring="Аудио прослушивание"
+Basic.AdvAudio.Monitoring.None="Выключить прослушивание"
+Basic.AdvAudio.Monitoring.MonitorOnly="Только прослушивание (заглушить вывод)"
+Basic.AdvAudio.Monitoring.Both="Прослушивание и вывод"
Basic.AdvAudio.AudioTracks="Дорожки"
Basic.Settings.Hotkeys="Горячие клавиши"
Basic.Settings.Hotkeys.Pair="Сочетания клавиш вместе с '%1' действуют как переключатели"
-Basic.Hotkeys.StartStreaming="Запустить трансляцию"
-Basic.Hotkeys.StopStreaming="Остановить трансляцию"
-Basic.Hotkeys.StartRecording="Начать запись"
-Basic.Hotkeys.StopRecording="Остановить запись"
Basic.Hotkeys.SelectScene="Перейти на сцену"
Basic.SystemTray.Show="Показать"
@@ -546,4 +615,5 @@ SceneItemHide="Скрыть '%1'"
OutputWarnings.NoTracksSelected="Вы должны выбрать хотя бы одну звуковую дорожку"
OutputWarnings.MultiTrackRecording="Предупреждение: Некоторые форматы (такие как FLV) не поддерживают множественные звуковые дорожки"
+OutputWarnings.MP4Recording="Внимание: Записи, сохраненные в MP4 будут нечитаемы, если файл не будет завершен (например, в результате BSOD'а, потери напряжения в сети и т.д.). Если вы хотите записывать несколько аудио дорожек, рассмотрите использование MKV, и последующее ремультиплексирование в MP4 после завершения записи (Файл -> Ремультиплексирование записей)"
diff --git a/UI/data/locale/sk-SK.ini b/UI/data/locale/sk-SK.ini
index bec05a6..4b292f0 100644
--- a/UI/data/locale/sk-SK.ini
+++ b/UI/data/locale/sk-SK.ini
@@ -8,16 +8,19 @@ Cancel="Zrušiť"
Close="Zatvoriť"
Save="Uložiť"
Discard="Zahodiť"
+Disable="Zakázané"
Yes="Áno"
No="Nie"
Add="Pridať"
Remove="Odobrať"
Rename="Premenovať"
+Filters="Filtre"
Properties="Vlastnosti"
MoveUp="Posunúť vyššie"
MoveDown="Posunúť nižšie"
Settings="Nastavenia"
Display="Monitor"
+Name="Meno"
Exit="Ukončiť"
Mixer="Zmiešavač"
Browse="Prehľadávať"
@@ -32,8 +35,22 @@ Untitled="Bez názvu"
New="Nový"
Duplicate="Duplikovať"
Enable="Povoliť"
+Transition="Prechod"
+QuickTransitions="Rýchle prechody"
+Left="Vľavo"
+Right="Vpravo"
+Top="Hore"
+Bottom="Dole"
+Reset="Vynulovať"
+Hours="Hodín"
+Minutes="Minúty"
+Seconds="Sekundy"
+QuickTransitions.DuplicateScene="Duplikovať scénu"
+
+Basic.TransitionDuration="Trvanie"
+Basic.TogglePreviewProgramMode="Štúdiový režim"
TitleBar.Profile="Profil"
@@ -45,7 +62,11 @@ NameExists.Text="Tento názov sa už používa."
NoNameEntered.Title="Prosím, zadajte platný názov"
NoNameEntered.Text="Nemôžete použiť prázdne názvy."
+ConfirmStart.Title="Spustiť stream?"
+ConfirmStart.Text="Naozaj chcete spustiť stream?"
+ConfirmStop.Title="Zastaviť stream?"
+ConfirmStop.Text="Naozaj chcete zastaviť stream?"
ConfirmExit.Title="Ukončiť OBS?"
ConfirmExit.Text="OBS je momentálne aktívny. Všetky prúdy údajov/záznamy sa ukončia. Naozaj pokračovať?"
@@ -53,10 +74,14 @@ ConfirmExit.Text="OBS je momentálne aktívny. Všetky prúdy údajov/záznamy
ConfirmRemove.Title="Potvrdenie odobratia"
ConfirmRemove.Text="Naozaj si prajete odobrať '$1'?"
+
Output.ConnectFail.Title="Spojenie sa nepodarilo"
Output.ConnectFail.BadPath="Neplatná cesta alebo URL. Prosím, skontrolujte, či sú vaše nastavenia správne."
Output.ConnectFail.ConnectFailed="Spojenie so serverom sa nepodarilo"
+Output.RecordFail.Title="Nepodarilo sa spustiť nahrávanie"
+Output.RecordNoSpace.Title="Nedostatok miesta na disku"
+Output.RecordError.Title="Chyba nahrávania"
Output.BadPath.Title="Nesprávna cesta k súboru"
@@ -68,6 +93,7 @@ LicenseAgreement.Exit="Ukončiť"
Remux.SourceFile="OBS nahrávka"
Remux.TargetFile="Cieľový súbor"
+Remux.OBSRecording="OBS nahrávanie"
Remux.SelectRecording="Vybrať OBS nahrávku …"
Remux.SelectTarget="Vyberte cieľový súbor …"
Remux.FileExistsTitle="Cieľový súbor existuje"
@@ -83,6 +109,7 @@ Basic.DisplayCapture="Zachytávanie monitora"
+
Basic.Main.AddSceneDlg.Title="Pridať scénu"
Basic.Main.AddSceneDlg.Text="Prosím, zadajte názov scény"
@@ -176,7 +203,9 @@ Basic.MainMenu.Edit.Order.MoveToTop="Premies&tniť navrch"
Basic.MainMenu.Edit.Order.MoveToBottom="Premiestniť naspodok (&B)"
+Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Tools="Nás&troje"
Basic.MainMenu.Help="Pomoc (&H)"
Basic.MainMenu.Help.Logs="&Log súbory"
@@ -188,12 +217,15 @@ Basic.Settings.ConfirmTitle="Potvrdenie zmien"
Basic.Settings.Confirm="Máte neuložené zmeny. Chcete uložiť zmeny?"
Basic.Settings.General="Všeobecné"
+Basic.Settings.General.Theme="Vzhľad"
+Basic.Settings.General.Language="Jazyk"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Typ streamu"
Basic.Settings.Output="Výstup"
Basic.Settings.Output.Mode="Režim výstupu"
+Basic.Settings.Output.Mode.Simple="Jednoduchý"
Basic.Settings.Output.VideoBitrate="Bitrate videa"
Basic.Settings.Output.AudioBitrate="Bitrate zvuku"
Basic.Settings.Output.Reconnect="Automaticky znovupripájať"
@@ -201,7 +233,12 @@ Basic.Settings.Output.RetryDelay="Čas medzi pokusmi (sekundy)"
Basic.Settings.Output.MaxRetries="Maximálny počet pokusov"
Basic.Settings.Output.Advanced="Povoliť pokročilé nastavenia enkodéra"
+Basic.Settings.Output.Adv.Audio.Track1="Stopa 1"
+Basic.Settings.Output.Adv.Audio.Track2="Stopa 2"
+Basic.Settings.Output.Adv.Audio.Track3="Stopa 3"
+Basic.Settings.Output.Adv.Audio.Track4="Stopa 4"
+Basic.Settings.Output.Adv.Recording.Type="Typ"
diff --git a/UI/data/locale/sl-SI.ini b/UI/data/locale/sl-SI.ini
index 780c52f..ac0a831 100644
--- a/UI/data/locale/sl-SI.ini
+++ b/UI/data/locale/sl-SI.ini
@@ -31,6 +31,7 @@ DroppedFrames="Izpuščene sličice %1 (%2 %)"
+
NameExists.Title="Ime že obstaja"
NameExists.Text="Ime je že v uporabi."
@@ -44,6 +45,7 @@ ConfirmExit.Title="Zapusti OBS?"
ConfirmRemove.Title="Potrdite odstranitev"
ConfirmRemove.Text="Ali ste prepričani, da želite odstraniti '$ 1'?"
+
Output.ConnectFail.Title="Povezava ni uspela"
Output.ConnectFail.BadPath="Neveljavna pot ali URL povezava. Prosimo, preverite vaše nastavitve za potrditev, da so veljavne."
Output.ConnectFail.ConnectFailed="Ni uspelo povezati s strežnikom"
@@ -81,6 +83,7 @@ Basic.DisplayCapture="Zajemanje zaslona"
+
Basic.Main.AddSceneDlg.Title="Dodaj seceno"
Basic.Main.AddSceneDlg.Text="Prosimo, vnesite ime scene"
diff --git a/UI/data/locale/sr-CS.ini b/UI/data/locale/sr-CS.ini
index 2097d04..cc86301 100644
--- a/UI/data/locale/sr-CS.ini
+++ b/UI/data/locale/sr-CS.ini
@@ -48,6 +48,12 @@ Left="Sleva"
Right="Zdesna"
Top="Odozgo"
Bottom="Odozdo"
+Reset="Poništi"
+Hours="Sati"
+Minutes="Minuta"
+Seconds="Sekundi"
+Deprecated="Prevaziđeno"
+
QuickTransitions.SwapScenes="Zameni scene pregleda/izlaza nakon prelaza"
QuickTransitions.SwapScenesTT="Zamenjuje scene pregleda i izlaza nakon prelaza (ako originalna scena izlaza još uvek postoji).\nOvo neće poništiti promene koje su načinjene nad originalnom scenom izlaza."
@@ -89,6 +95,7 @@ ConfirmRemove.Title="Potvrdi izbacivanje"
ConfirmRemove.Text="Da li ste sigurni da želite izbaciti '$1'?"
ConfirmRemove.TextMultiple="Da li ste sigurni da želite izbaciti %1 stavke?"
+
Output.ConnectFail.Title="Neuspešno povezivanje"
Output.ConnectFail.BadPath="Neispravna putanja ili URL konekcije. Molim proverite vaša podešavanja da potvrdite njihovu ispravnost."
Output.ConnectFail.ConnectFailed="Neuspešno povezivanje na server"
@@ -163,6 +170,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Prvo gornje polje"
Deinterlacing.BottomFieldFirst="Prvo donje polje"
+
Basic.Main.AddSceneDlg.Title="Dodaj scenu"
Basic.Main.AddSceneDlg.Text="Molim unesite ime scene"
@@ -281,6 +289,10 @@ Basic.MainMenu.Edit.Redo="U&radi ponovo"
Basic.MainMenu.Edit.UndoAction="Vrati $1 (&U)"
Basic.MainMenu.Edit.RedoAction="U&radi ponovo $1"
Basic.MainMenu.Edit.LockPreview="Zak&ljučaj prikaz"
+Basic.MainMenu.Edit.Scale="Pregled &skaliranja"
+Basic.MainMenu.Edit.Scale.Window="Skaliraj na veličinu prozora"
+Basic.MainMenu.Edit.Scale.Canvas="Platno (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Izlaz (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transformiši"
Basic.MainMenu.Edit.Transform.EditTransform="Izm&eni transformaciju..."
Basic.MainMenu.Edit.Transform.ResetTransform="Poništi t&ransformaciju"
@@ -337,7 +349,6 @@ Basic.Settings.General.SourceSnapping="Privlačenje izvora ka drugim izvorima"
Basic.Settings.General.SnapDistance="Osetljivost privlačenja"
Basic.Settings.General.RecordWhenStreaming="Automatsko snimanje pri emitovanju"
Basic.Settings.General.KeepRecordingWhenStreamStops="Nastavi snimati kada se emitovanje zaustavi"
-Basic.Settings.General.SysTrayEnabled="Omogući ikonicu u sistemskom panelu"
Basic.Settings.General.SysTrayWhenStarted="Pri pokretanju minimiziraj na ikonicu u sistemskom panelu"
Basic.Settings.Stream="Strim"
@@ -368,6 +379,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Upozorenje za kvalitet bez gub
Basic.Settings.Output.Simple.Warn.MultipleQSV="Upozorenje: Ne možete koristi više odvojenih QSV enkodera kada emitujete i snimate u isto vreme. Ako želite da emitujete i snimate u isto vreme, molim promenite ili enkoder snimanja ili enkoder emitovanja."
Basic.Settings.Output.Simple.Encoder.Software="Softverski (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Mašinski (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Mašinski (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Mašinski (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Softverski (x264 niska upotreba procesora, povećava veličinu datoteke)"
Basic.Settings.Output.VideoBitrate="Protok videa"
@@ -487,10 +499,6 @@ Basic.AdvAudio.AudioTracks="Izvori"
Basic.Settings.Hotkeys="Prečice"
Basic.Settings.Hotkeys.Pair="Kombinacije tastera deljene sa '%1' se ponašaju kao prekidači"
-Basic.Hotkeys.StartStreaming="Započni strimovanje"
-Basic.Hotkeys.StopStreaming="Zaustavi strimovanje"
-Basic.Hotkeys.StartRecording="Počni snimanje"
-Basic.Hotkeys.StopRecording="Zaustavi snimanje"
Basic.Hotkeys.SelectScene="Prebaci na scenu"
Basic.SystemTray.Show="Prikaži"
diff --git a/UI/data/locale/sr-SP.ini b/UI/data/locale/sr-SP.ini
index a9c5a44..f76cb37 100644
--- a/UI/data/locale/sr-SP.ini
+++ b/UI/data/locale/sr-SP.ini
@@ -48,6 +48,12 @@ Left="Слева"
Right="Здесна"
Top="Одозго"
Bottom="Одоздо"
+Reset="Поништи"
+Hours="Сати"
+Minutes="Минута"
+Seconds="Секунди"
+Deprecated="Превазиђено"
+
QuickTransitions.SwapScenes="Замени сцене прегледа/излаза након прелаза"
QuickTransitions.SwapScenesTT="Замењује сцене прегледа и излаза након прелаза (ако оригинална сцена још увек постоји).\nОво неће поништити промене које су начињене над оригиналном сценом излаза."
@@ -89,6 +95,7 @@ ConfirmRemove.Title="Потврди избацивање"
ConfirmRemove.Text="Да ли сте сигурни да желите избацити '$1'?"
ConfirmRemove.TextMultiple="Да ли сте сигурни да желите избацити %1 ставке?"
+
Output.ConnectFail.Title="Неуспешно повезивање"
Output.ConnectFail.BadPath="Неисправна путања или URL конекције. Молим проверите ваша подешавања да потврдите њихову исправност."
Output.ConnectFail.ConnectFailed="Неуспешно повезивање на сервер"
@@ -163,6 +170,7 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Прво горње поље"
Deinterlacing.BottomFieldFirst="Прво доње поље"
+
Basic.Main.AddSceneDlg.Title="Додај сцену"
Basic.Main.AddSceneDlg.Text="Молим унесите име сцене"
@@ -281,6 +289,10 @@ Basic.MainMenu.Edit.Redo="Уради поново (&R)"
Basic.MainMenu.Edit.UndoAction="Врати $1 (&U)"
Basic.MainMenu.Edit.RedoAction="Уради поново $1 (&R)"
Basic.MainMenu.Edit.LockPreview="Закључај приказ (&L)"
+Basic.MainMenu.Edit.Scale="Преглед скалирања (&s)"
+Basic.MainMenu.Edit.Scale.Window="Скалирај на величину прозора"
+Basic.MainMenu.Edit.Scale.Canvas="Платно (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Излаз (%1x%2)"
Basic.MainMenu.Edit.Transform="&Трансформиши"
Basic.MainMenu.Edit.Transform.EditTransform="Изм&ени трансформацију..."
Basic.MainMenu.Edit.Transform.ResetTransform="Поништи трансформацију (&R)"
@@ -337,7 +349,6 @@ Basic.Settings.General.SourceSnapping="Привлачење извора ка д
Basic.Settings.General.SnapDistance="Осетљивост привлачења"
Basic.Settings.General.RecordWhenStreaming="Аутоматско снимање при емитовању"
Basic.Settings.General.KeepRecordingWhenStreamStops="Настави снимати када се емитовање заустави"
-Basic.Settings.General.SysTrayEnabled="Омогући иконицу у системском панелу"
Basic.Settings.General.SysTrayWhenStarted="При покретању минимизирај на иконицу у системском панелу"
Basic.Settings.Stream="Стрим"
@@ -368,6 +379,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Упозорење за ква
Basic.Settings.Output.Simple.Warn.MultipleQSV="Упозорење: Не можете користити више одвојених QSV енкодера када емитујете и снимате у исто време. Ако желите да емитујете и снимате у исто време, молим промените или енкодер снимања или енкодер емитовања."
Basic.Settings.Output.Simple.Encoder.Software="Софтверски (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Машински (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Машински (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Машински (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Софтверски (x264 ниска употреба процесора, повећава величину датотеке)"
Basic.Settings.Output.VideoBitrate="Проток видеа"
@@ -487,10 +499,6 @@ Basic.AdvAudio.AudioTracks="Извори"
Basic.Settings.Hotkeys="Пречице"
Basic.Settings.Hotkeys.Pair="Комбинације тастера дељене са '%1' се понашају као прекидачи"
-Basic.Hotkeys.StartStreaming="Почни стримовање"
-Basic.Hotkeys.StopStreaming="Заустави стримовање"
-Basic.Hotkeys.StartRecording="Почни снимање"
-Basic.Hotkeys.StopRecording="Заустави снимање"
Basic.Hotkeys.SelectScene="Пребаци на сцену"
Basic.SystemTray.Show="Прикажи"
diff --git a/UI/data/locale/sv-SE.ini b/UI/data/locale/sv-SE.ini
index 81c34c1..c18a4ae 100644
--- a/UI/data/locale/sv-SE.ini
+++ b/UI/data/locale/sv-SE.ini
@@ -28,9 +28,9 @@ Browse="Bläddra"
Mono="Mono"
Stereo="Stereo"
DroppedFrames="Tappade bildrutor %1 (%2%)"
-PreviewProjector="Fullskärm projektor (Förhandsvisa)"
-SceneProjector="Fullskärm projektor (scen)"
-SourceProjector="Fullskärm projektor (källa)"
+PreviewProjector="Fullskärmsprojektor (förhandsvisning)"
+SceneProjector="Fullskärmsprojektor (scen)"
+SourceProjector="Fullskärmsprojektor (källa)"
Clear="Rensa"
Revert="Återgå"
Show="Visa"
@@ -49,11 +49,33 @@ Right="Höger"
Top="Överkant"
Bottom="Nederkant"
Reset="Återställ"
+Hours="timmar"
+Minutes="minuter"
+Seconds="sekunder"
+Deprecated="Föråldrat"
+ReplayBuffer="Reprisbuffert"
+Import="Importera"
+Export="Exportera"
+
+Updater.Title="Ny uppdatering tillgänglig"
+Updater.Text="Det finns en ny uppdatering tillgänglig:"
+Updater.UpdateNow="Uppdatera nu"
+Updater.RemindMeLater="Påminn mig senare"
+Updater.Skip="Hoppa över version"
+Updater.Running.Title="Programmet körs för tillfället"
+Updater.Running.Text="Utmatningar pågår för tillfället, stäng ned alla aktiva utmatningar innan du uppdaterar"
+Updater.NoUpdatesAvailable.Title="Inga tillgängliga uppdateringar"
+Updater.NoUpdatesAvailable.Text="Inga uppdateringar är tillgängliga för närvarande"
+Updater.FailedToLaunch="Misslyckades att starta uppdateringen"
+Updater.GameCaptureActive.Title="Spelkälla aktiv"
+Updater.GameCaptureActive.Text="Hook-biblioteket för spelkällor används för tillfället. Stäng alla spel/program som spelas in (eller starta om Windows) och försök igen."
QuickTransitions.SwapScenes="Byt plats på Förhandsvisnings-/utdatascenerna efter skifte"
QuickTransitions.SwapScenesTT="Byter plats på förhandsvisnings- och utdatascenerna efter övergång (om utdatans originalscen fortfarande finns). \nDet här kommer inte att ångra några förändringar i utdatans originalscen."
QuickTransitions.DuplicateScene="Duplicera scen"
-QuickTransitions.EditProperties="Duplicera källa"
+QuickTransitions.DuplicateSceneTT="När du redigerar samma scen kan du redigera transformering/synligheten för källor utan att modifiera utmatningen.\nFör att redigera egenskaper för källor utan att modifiera utmatningen aktiverar du 'Duplicera källor'.\nNär detta värde ändras kommer den aktuella utmatningsscenen återställas (om den fortfarande finns)."
+QuickTransitions.EditProperties="Duplicera källor"
+QuickTransitions.EditPropertiesTT="När du redigerar samma scen kan du redigera egenskaperna för källor utan att modifiera utmatningen.\nDetta fungerar endast om 'Duplicera scen' är aktiverad.\nVissa källor (som mediakällor) stöder inte detta och kan inte redigeras separat.\nNär detta värde ändras kommer den aktuella utmatningsscenen återställas (om den fortfarande finns).\n\nVarning: Eftersom källor kommer att dupliceras kan detta kräva extra system- eller videoresurser."
QuickTransitions.HotkeyName="Snabba övergång: %1"
Basic.AddTransition="Lägg till konfigurerbar övergång"
@@ -88,6 +110,11 @@ ConfirmRemove.Title="Bekräfta borttagning"
ConfirmRemove.Text="Vill du verkligen ta bort '$1'?"
ConfirmRemove.TextMultiple="Är du säker på att du vill ta bort %1 poster?"
+Output.StartStreamFailed="Misslyckades att starta strömning"
+Output.StartRecordingFailed="Misslyckades att starta inspelning"
+Output.StartReplayFailed="Misslyckades att starta reprisbuffert"
+Output.StartFailedGeneric="Misslyckades att starta utmatningen. Kolla loggen för detaljer.\n\nOBS: Om du använder kodarna NVENC eller AMD, se till att dina grafikdrivrutiner är uppdaterade."
+
Output.ConnectFail.Title="Anslutning misslyckades"
Output.ConnectFail.BadPath="Ogiltig sökväg eller anslutnings-URL. Kontrollera att dina inställningar är korrekta."
Output.ConnectFail.ConnectFailed="Kunde inte ansluta till servern"
@@ -101,6 +128,8 @@ Output.RecordNoSpace.Title="Otillräckligt diskutrymme"
Output.RecordNoSpace.Msg="Det finns inte tillräckligt med diskutrymme för att fortsätta inspelningen."
Output.RecordError.Title="Inspelningsfel"
Output.RecordError.Msg="Ett okänt fel uppstod vid inspelning."
+Output.ReplayBuffer.NoHotkey.Title="Ingen angivet kortkommando!"
+Output.ReplayBuffer.NoHotkey.Msg="Inget kortkommando för att spara reprisbufferten har angivits. Ange kortkommandot \"Spara\" för att kunna spara reprisinspelningar."
Output.BadPath.Title="Ogiltig sökväg"
Output.BadPath.Text="Den angivna sökvägen för utmatningsfil är ogiltig. Kontrollera att dina inställningar är korrekta och att en giltig sökväg har angetts."
@@ -142,7 +171,7 @@ Basic.AuxDevice4="Mic/Aux 4"
Basic.Scene="Scen"
Basic.DisplayCapture="Bildskärmskälla"
-Basic.Main.PreviewConextMenu.Enable="Förhandsvisa"
+Basic.Main.PreviewConextMenu.Enable="Aktivera förhandsvisning"
ScaleFiltering="Skalningsfiltrering"
ScaleFiltering.Point="Punkt"
@@ -162,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Övre fältet först"
Deinterlacing.BottomFieldFirst="Nedre fältet först"
+VolControl.SliderUnmuted="Volymreglage för \"%1\": %2"
+VolControl.SliderMuted="Volymreglage för \"%1\": %2 (tyst för tillfället)"
+VolControl.Mute="Tysta \"%1\""
+VolControl.Properties="Egenskaper för \"%1\""
+
Basic.Main.AddSceneDlg.Title="Lägg till scen"
Basic.Main.AddSceneDlg.Text="Vänligen ange ett namn för scenen"
@@ -256,9 +290,12 @@ Basic.Main.Scenes="Scener"
Basic.Main.Sources="Källor"
Basic.Main.Connecting="Ansluter..."
Basic.Main.StartRecording="Starta inspelning"
+Basic.Main.StartReplayBuffer="Starta reprisbuffert"
Basic.Main.StartStreaming="Börja strömma"
Basic.Main.StopRecording="Stoppa inspelning"
Basic.Main.StoppingRecording="Stoppar inspelning..."
+Basic.Main.StopReplayBuffer="Stoppa reprisbuffert"
+Basic.Main.StoppingReplayBuffer="Stoppar reprisbuffert..."
Basic.Main.StopStreaming="Sluta strömma"
Basic.Main.StoppingStreaming="Stoppar ström..."
Basic.Main.ForceStopStreaming="Sluta strömma (ignorera fördröjning)"
@@ -267,7 +304,7 @@ Basic.MainMenu.File="&Arkiv"
Basic.MainMenu.File.Export="&Exportera"
Basic.MainMenu.File.Import="&Importera"
Basic.MainMenu.File.ShowRecordings="Visa &inspelningar"
-Basic.MainMenu.File.Remux="Re&mux Inspelningar"
+Basic.MainMenu.File.Remux="Re&muxa inspelningar"
Basic.MainMenu.File.Settings="&Inställningar"
Basic.MainMenu.File.ShowSettingsFolder="Visa inställningsmapp"
Basic.MainMenu.File.ShowProfileFolder="Visa profilmapp"
@@ -280,8 +317,14 @@ Basic.MainMenu.Edit.Redo="&Gör om"
Basic.MainMenu.Edit.UndoAction="&Ångra $1"
Basic.MainMenu.Edit.RedoAction="&Gör om $1"
Basic.MainMenu.Edit.LockPreview="&Lås förhandsvisning"
+Basic.MainMenu.Edit.Scale="Förhandsvisa &skalning"
+Basic.MainMenu.Edit.Scale.Window="Skala till fönster"
+Basic.MainMenu.Edit.Scale.Canvas="Kanvas (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Utmatning (%1x%2)"
Basic.MainMenu.Edit.Transform="&Omvandla"
Basic.MainMenu.Edit.Transform.EditTransform="&Redigera omvandling..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Kopiera transformering"
+Basic.MainMenu.Edit.Transform.PasteTransform="Klistra in transformering"
Basic.MainMenu.Edit.Transform.ResetTransform="&Återställ omvandling"
Basic.MainMenu.Edit.Transform.Rotate90CW="Rotera 90 grader medsols &>"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotera 90 grader motsols &<"
@@ -306,6 +349,12 @@ Basic.MainMenu.View.StatusBar="&Statusfält"
Basic.MainMenu.SceneCollection="&Scensamling"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Importera profil"
+Basic.MainMenu.Profile.Export="Exportera profil"
+Basic.MainMenu.SceneCollection.Import="Importera scensamling"
+Basic.MainMenu.SceneCollection.Export="Exportera scensamling"
+Basic.MainMenu.Profile.Exists="Profilen finns redan"
+Basic.MainMenu.SceneCollection.Exists="Scensamlingen finns redan"
Basic.MainMenu.Tools="&Verktyg"
@@ -325,8 +374,10 @@ Basic.Settings.Confirm="Du har osparade ändringar. Vill du spara ändringarna?"
Basic.Settings.General="Allmänt"
Basic.Settings.General.Theme=" Tema"
Basic.Settings.General.Language="Språk"
+Basic.Settings.General.EnableAutoUpdates="Sök efter uppdateringar automatiskt vid start"
Basic.Settings.General.WarnBeforeStartingStream="Visa bekräftelsedialog när ström startas"
Basic.Settings.General.WarnBeforeStoppingStream="Visa bekräftelsedialog när ström stoppas"
+Basic.Settings.General.Projectors="Projektorer"
Basic.Settings.General.HideProjectorCursor="Dölj pekaren över projektorer"
Basic.Settings.General.ProjectorAlwaysOnTop="Lägg alltid projektorer överst"
Basic.Settings.General.Snapping="Fäst justerbara källor"
@@ -336,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Fäst källor till andra källor"
Basic.Settings.General.SnapDistance="Fästkänslighet"
Basic.Settings.General.RecordWhenStreaming="Spela automatiskt in vid strömning"
Basic.Settings.General.KeepRecordingWhenStreamStops="Fortsätt spela in när strömmen stoppas"
-Basic.Settings.General.SysTrayEnabled="Aktivera ikon i meddelandefältet"
+Basic.Settings.General.ReplayBufferWhileStreaming="Starta reprisbufferten automatiskt vid strömning"
+Basic.Settings.General.KeepReplayBufferStreamStops="Håll reprisbufferten aktiv när ström stoppas"
+Basic.Settings.General.SysTray="Systemfält"
Basic.Settings.General.SysTrayWhenStarted="Minimera till meddelandefältet vid start"
+Basic.Settings.General.SystemTrayHideMinimize="Minimera alltid till meddelandefältet i stället för aktivitetsfältet"
+Basic.Settings.General.SaveProjectors="Spara projektorer vid avslut"
Basic.Settings.Stream="Ström"
Basic.Settings.Stream.StreamType="Strömtyp"
@@ -352,6 +407,14 @@ Basic.Settings.Output.Mode="Utmatningsläge"
Basic.Settings.Output.Mode.Simple="Simpel"
Basic.Settings.Output.Mode.Adv="Avancerat"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg-utmatning"
+Basic.Settings.Output.UseReplayBuffer="Aktivera reprisbuffert"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximal repristid (sekunder)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximalt minne (Megabyte)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Uppskattad minnesanvändning: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Kan inte uppskatta minnesanvändningen. Ange maximal minnesgräns."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(OBS: Se till att ange ett kortkommando för reprisbufferten i avsnittet för kortkommandon)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Filnamnsprefix för reprisbuffert"
+Basic.Settings.Output.ReplayBuffer.Suffix="Suffix"
Basic.Settings.Output.Simple.SavePath="Inspelningssökväg"
Basic.Settings.Output.Simple.RecordingQuality="Inspelningskvalitet"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Samma som ström"
@@ -367,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Varning angående förlustfri
Basic.Settings.Output.Simple.Warn.MultipleQSV="Varning: Du kan inte använda flera separata QSV-kodare när du streamar och spelar in samtidigt. Om du vill streama och spela in samtidigt, vänligen ändra inspelnings-kodek eller streaming-kodek."
Basic.Settings.Output.Simple.Encoder.Software="Programvara (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Hårdvara (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Hårdvara (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Hårdvara (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Mjukvaru-kodek (x264-förinställning för lågt CPU-användning, ökar filstorleken)"
Basic.Settings.Output.VideoBitrate="Bithastighet för video"
@@ -388,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Spår 1"
Basic.Settings.Output.Adv.Audio.Track2="Spår 2"
Basic.Settings.Output.Adv.Audio.Track3="Spår 3"
Basic.Settings.Output.Adv.Audio.Track4="Spår 4"
+Basic.Settings.Output.Adv.Audio.Track5="Spår 5"
+Basic.Settings.Output.Adv.Audio.Track6="Spår 6"
Basic.Settings.Output.Adv.Recording="Inspelning"
Basic.Settings.Output.Adv.Recording.Type="Typ"
@@ -415,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Videokodar-inställningar (om
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Ljudkodare"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Ljudkodar-inställningar (om något)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxerinställningar (om det finns)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Intervall för keyframes (bildrutor)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Visa alla kodekar (även de som eventuellt inte är kompatibla)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -468,11 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV-färgrymd"
Basic.Settings.Advanced.Video.ColorRange="YUV färgområde"
Basic.Settings.Advanced.Video.ColorRange.Partial="Partiell"
Basic.Settings.Advanced.Video.ColorRange.Full="Full"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Ljuduppspelningsenhet"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Standard"
Basic.Settings.Advanced.StreamDelay="Strömfördröjning"
Basic.Settings.Advanced.StreamDelay.Duration="Varaktighet (sekunder)"
+Basic.Settings.Advanced.StreamDelay.Preserve="Behåll stoppunkten (öka fördröjningen) vid återanslutning"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Uppskattad minnesanvändning: %1 MB"
Basic.Settings.Advanced.Network="Nätverk"
Basic.Settings.Advanced.Network.BindToIP="Bind till IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Aktivera ny nätverkskod"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Låg latens-läge"
Basic.AdvAudio="Avancerade ljudinställningar"
Basic.AdvAudio.Name="Namn"
@@ -480,14 +553,14 @@ Basic.AdvAudio.Volume="Volym (%)"
Basic.AdvAudio.Mono="Nedmixa till mono"
Basic.AdvAudio.Panning="Panorering"
Basic.AdvAudio.SyncOffset="Sync Offset (ms)"
+Basic.AdvAudio.Monitoring="Ljuduppspelning"
+Basic.AdvAudio.Monitoring.None="Monitor av"
+Basic.AdvAudio.Monitoring.Both="Monitor och utgång"
Basic.AdvAudio.AudioTracks="Spår"
Basic.Settings.Hotkeys="Kortkommandon"
+Basic.Settings.Hotkeys.Pair="Tangentkombinationer som delas med \"%1\" fungerar som strömbrytare"
-Basic.Hotkeys.StartStreaming="Börja strömma"
-Basic.Hotkeys.StopStreaming="Sluta strömma"
-Basic.Hotkeys.StartRecording="Starta inspelning"
-Basic.Hotkeys.StopRecording="Stoppa inspelning"
Basic.Hotkeys.SelectScene="Byt till scen"
Basic.SystemTray.Show="Visa"
@@ -541,4 +614,5 @@ SceneItemHide="Dölj '%1'"
OutputWarnings.NoTracksSelected="Du måste välja minst ett spår"
OutputWarnings.MultiTrackRecording="Varning: En del format (t.ex. FLV) stöder inte flera spår för varje inspelning"
+OutputWarnings.MP4Recording="Varning: Inspelningar som sparas som MP4 kommer inte att kunna återställas om filen inte kan slutföras (d.v.s. om en datorkrasch, strömavbrott, etc. skulle inträffa). Om du vill spela in flera ljudspår, överväg att använda MKV och remuxa inspelningen till mp4 när den är färdig (Arkiv->Remuxa inspelningar)"
diff --git a/UI/data/locale/ta-IN.ini b/UI/data/locale/ta-IN.ini
index c79b30b..8a8cce8 100644
--- a/UI/data/locale/ta-IN.ini
+++ b/UI/data/locale/ta-IN.ini
@@ -88,6 +88,9 @@ New="புதிய"
+
+
+
diff --git a/UI/data/locale/th-TH.ini b/UI/data/locale/th-TH.ini
index 0509a7c..0d149d4 100644
--- a/UI/data/locale/th-TH.ini
+++ b/UI/data/locale/th-TH.ini
@@ -5,19 +5,35 @@ Region="ประเทศไทย"
OK="ตกลง"
Apply="นำไปใช้"
Cancel="ยกเลิก"
+Close="ปิด"
+Save="บันทึก"
+Discard="ละทิ้ง"
+Disable="ไม่ใช้"
Yes="ใช่"
No="ไม่"
Add="เพิ่ม"
Remove="ลบ"
Rename="เปลี่ยนชื่อ"
+Filters="ฟิลเตอร์"
Properties="คุณสมบัติ"
MoveUp="เลื่อนขึ้น"
MoveDown="เลื่อนลง"
Settings="ตั้งค่า"
+Display="แสดงผล"
+Name="ชื่อ"
Exit="ออก"
Browse="เปิดหา"
Mono="โมโน"
Stereo="สเตอริโอ"
+PreviewProjector="แสดงผลแบบเต็มจอ (ตัวอย่าง)"
+Clear="ล้าง"
+Revert="กลับค่าเดิม"
+Show="แสดง"
+Hide="ซ่อน"
+Untitled="ไม่มีชื่อ"
+New="ใหม่"
+Enable="เปิดใช้งาน"
+
@@ -31,6 +47,7 @@ Stereo="สเตอริโอ"
ConfirmRemove.Title="ยืนยันการลบ"
ConfirmRemove.Text="คุณแน่ใจแล้วหรือที่จะลบ '$1'?"
+
Output.ConnectFail.Title="ไม่สามารถเชื่อมต่อได้"
Output.ConnectFail.ConnectFailed="ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์"
Output.ConnectFail.Disconnected="ถูกตัดออกจากเซิร์ฟเวอร์"
@@ -51,6 +68,7 @@ Basic.Scene="ฉาก"
+
Basic.Main.AddSceneDlg.Title="เพิ่มฉาก"
Basic.Main.DefaultSceneName.Text="ฉาก %1"
diff --git a/UI/data/locale/tr-TR.ini b/UI/data/locale/tr-TR.ini
index e7c88e4..c33cad1 100644
--- a/UI/data/locale/tr-TR.ini
+++ b/UI/data/locale/tr-TR.ini
@@ -8,7 +8,7 @@ Cancel="İptal"
Close="Kapat"
Save="Kaydet"
Discard="Vazgeç"
-Disable="Devre dışı bırak"
+Disable="Devre Dışı Bırak"
Yes="Evet"
No="Hayır"
Add="Ekle"
@@ -20,7 +20,7 @@ Properties="Özellikler"
MoveUp="Yukarı Taşı"
MoveDown="Aşağı Taşı"
Settings="Ayarlar"
-Display="Görüntüle"
+Display="Ekran"
Name="İsim"
Exit="Çık"
Mixer="Karıştırıcı"
@@ -39,34 +39,80 @@ Untitled="İsimsiz"
New="Yeni"
Duplicate="Çoğalt"
Enable="Etkinleştir"
-DisableOSXVSync="OSX V-Sync Devre Dışı Bırakma"
+DisableOSXVSync="OSX V-Sync Devre Dışı Bırak"
+ResetOSXVSyncOnExit="OSX V-Sync'i Çıkışta Sıfırla"
+HighResourceUsage="Kodlama aşırı yüklendi! Video ayarlarını kapatmayı veya daha hızlı bir kodlama ön ayarını kullanmayı düşünün."
Transition="Geçiş"
QuickTransitions="Hızlı Geçiş"
Left="Sol"
Right="Sağ"
Top="Üst"
Bottom="Alt"
+Reset="Sıfırla"
+Hours="Saat"
+Minutes="Dakika"
+Seconds="Saniye"
+Deprecated="Kullanım dışı"
+ReplayBuffer="Tekrar Oynatma Arabelleği"
+Import="İçe Aktar"
+Export="Dışa Aktar"
+Updater.Title="Yeni güncelleme mevcut"
+Updater.Text="Mevcut yeni bir güncelleme var:"
+Updater.UpdateNow="Şimdi Güncelle"
+Updater.RemindMeLater="Daha sonra hatırlat"
+Updater.Skip="Sürümü Atla"
+Updater.Running.Title="Program şu anda etkin"
+Updater.Running.Text="Çıkışlar hala etkin, lütfen güncellemeye çalışmadan önce aktif çıkışları kapatın"
+Updater.NoUpdatesAvailable.Title="Güncelleme mevcut değil"
+Updater.NoUpdatesAvailable.Text="Şu anda mevcut hiçbir güncelleme yok"
+Updater.FailedToLaunch="Güncelleyici başlatılamadı"
+Updater.GameCaptureActive.Title="Oyun yakalama etkin"
+Updater.GameCaptureActive.Text="Oyun yakalama kanca kütüphanesi hala kullanımda. Lütfen yakalanmakta olan oyunları/programları kapatın (veya Windows'u yeniden başlatın) ve yeniden deneyin."
+QuickTransitions.SwapScenes="Geçişten Sonra Önizleme/Çıkış Sahnelerini Değiştir"
+QuickTransitions.SwapScenesTT="Geçişten sonra çıkış ve ön izleme sahnelerinin yerini değiştirir (çıkışın orijinal sahnesi hala mevcutsa).\n Bu çıkışın orijinal sahnesine yapılan değişiklikleri geri almayacaktır."
+QuickTransitions.DuplicateScene="Sahneyi Çoğalt"
+QuickTransitions.DuplicateSceneTT="Aynı sahneyi düzenlerken, çıkışı değiştirmeden kaynakların dönüşümünü veya görünülürlüğünü düzenlemeye izin verir.\nKaynakların özelliklerini çıkışı değiştirmeden düzenlemek için 'Kaynakları Çoğalt'ı etkinleştirin.\nBu değeri değiştirmek mevcut çıkış sahnesini sıfırlar (hala varsa)."
+QuickTransitions.EditProperties="Kaynakları Çoğalt"
+QuickTransitions.EditPropertiesTT="Aynı sahneyi düzenlerken, çıkışı değiştirmeden kaynakların özelliklerinin düzenlenmesine izin verir.\nSadece 'Sahneyi Çoğalt' etkinse kullanılabilir.\nBelli kaynaklar (yakalama ve medya kaynakları gibi) bunu desteklemez ve ayrı olarak düzenlenemez.\nBu değeri değiştirmek mevcut çıkış sahnesini sıfırlar (hala varsa).\n\nUyarı: Kaynaklar çoğaltılacağından, ek sistem ve video kaynağı gerektirebilir."
+QuickTransitions.HotkeyName="Hızlı Geçiş: %1"
+
+Basic.AddTransition="Yapılandırılabilir Geçiş Ekle"
+Basic.RemoveTransition="Yapılandırılabilir Geçiş Kaldır"
+Basic.TransitionProperties="Geçiş Özellikleri"
+Basic.SceneTransitions="Sahne Geçişleri"
Basic.TransitionDuration="Süre"
+Basic.TogglePreviewProgramMode="Stüdyo Modu"
+TransitionNameDlg.Text="Lütfen geçiş adını girin"
+TransitionNameDlg.Title="Geçiş Adı"
TitleBar.Profile="Profil"
TitleBar.Scenes="Sahneler"
-NameExists.Title="Bu isim zaten mevcut"
+NameExists.Title="İsim zaten mevcut"
NameExists.Text="Bu isim zaten kullanılıyor."
NoNameEntered.Title="Lütfen geçerli bir isim girin"
-NoNameEntered.Text="İsmi boş kullanamazsınız."
+NoNameEntered.Text="İsim boş olamaz."
+ConfirmStart.Title="Yayın Başlatılsın Mı?"
+ConfirmStart.Text="Yayını gerçekten başlatmak istiyor musunuz?"
+ConfirmStop.Title="Yayın Durdurulsun Mu?"
+ConfirmStop.Text="Yayını gerçekten durdurmak istiyor musunuz?"
ConfirmExit.Title="OBS'den Çıkılsın mı?"
ConfirmExit.Text="OBS şu anda etkin. Tüm yayınlar / kayıtlar kapatılacak. Çıkmak istediğinize emin misiniz?"
ConfirmRemove.Title="Kaldırmayı Onayla"
ConfirmRemove.Text="'$1''i kaldırmak istediğinizden emin misiniz?"
+ConfirmRemove.TextMultiple="%1 öğeyi kaldırmak istediğinizden emin misiniz?"
+
+Output.StartStreamFailed="Yayın işlemi başarısız oldu"
+Output.StartRecordingFailed="Kayıt işlemi başarısız oldu"
+Output.StartReplayFailed="Tekrar oynatma arabelleği başarısız oldu"
Output.ConnectFail.Title="Bağlantı kurulamadı"
Output.ConnectFail.BadPath="Bağlantı adresiniz geçersiz. Ayarlarınızı kontrol edin ve geçerli bir adres giriniz."
@@ -80,6 +126,8 @@ Output.RecordNoSpace.Title="Yetersiz disk alanı"
Output.RecordNoSpace.Msg="Kayıt'aa devam etmek yeterli disk alanı yok."
Output.RecordError.Title="Kayıt Hatası"
Output.RecordError.Msg="Kayıt anında bir hata oluştu."
+Output.ReplayBuffer.NoHotkey.Title="Kısayol tuşu ayarlanmadı!"
+Output.ReplayBuffer.NoHotkey.Msg="Yeniden oynatma arabelleği için ayarlı bir kısayol tuşu yok. Lütfen yeniden oynatma kayıtlarını kaydetmek için \"Kaydet\" kısayol tuşunu ayarlayın."
Output.BadPath.Title="Dosya Yolu Geçersiz"
Output.BadPath.Text="Ayarlanan dosya kayıt yolu geçersiz. Lütfen ayarlarınızı kontrol ederek geçerli bir dosya yolunun girilmiş olduğundan emin olunuz."
@@ -123,12 +171,33 @@ Basic.DisplayCapture="Ekran Yakalama"
Basic.Main.PreviewConextMenu.Enable="Önizlemeyi Etkinleştir"
+ScaleFiltering="Boyut Filtreleme"
+ScaleFiltering.Point="Nokta"
+ScaleFiltering.Bilinear="Bilinear"
+ScaleFiltering.Bicubic="Bikübik"
+ScaleFiltering.Lanczos="Lanczos"
+Deinterlacing="Deinterlacing"
+Deinterlacing.Discard="Discard"
+Deinterlacing.Retro="Retro"
+Deinterlacing.Blend="Blend"
+Deinterlacing.Blend2x="Blend 2x"
+Deinterlacing.Linear="Linear"
+Deinterlacing.Linear2x="Linear 2x"
+Deinterlacing.Yadif="Yadif"
+Deinterlacing.Yadif2x="Yadif 2x"
+Deinterlacing.TopFieldFirst="Önce Üst Alan"
+Deinterlacing.BottomFieldFirst="Önce Alt Alan"
+
+VolControl.SliderUnmuted="'%1' için ses kaydırıcı: %2"
+VolControl.SliderMuted="Повзунок гучності для '%1': %2 (şu anda sessiz)"
+VolControl.Mute="Sessiz '%1'"
+VolControl.Properties="'%1' için özellikler"
Basic.Main.AddSceneDlg.Title="Sahne Ekle"
Basic.Main.AddSceneDlg.Text="Lütfen sahne adını giriniz"
-Basic.Main.DefaultSceneName.Text="%1 Sahnesi"
+Basic.Main.DefaultSceneName.Text="Sahne %1"
Basic.Main.AddSceneCollection.Title="Sahne Koleksiyonu Ekle"
Basic.Main.AddSceneCollection.Text="Sahne koleksiyonunun isimini giriniz"
@@ -155,11 +224,16 @@ Basic.PropertiesWindow.ConfirmTitle="Ayarlar Değiştirildi"
Basic.PropertiesWindow.Confirm="Kaydedilmeyen değişikler var. Yaptığınız değişikleri kaydetmek istiyor musunuz?"
Basic.PropertiesWindow.NoProperties="Hiçbir özellik mevcut değil"
Basic.PropertiesWindow.AddFiles="Dosya Ekle"
+Basic.PropertiesWindow.AddDir="Dizin Ekle"
Basic.PropertiesWindow.AddURL="DosyaYolu/URL Ekle"
+Basic.PropertiesWindow.AddEditableListDir="'%1' dizinine ekle"
Basic.PropertiesWindow.AddEditableListFiles="Dosyaları '%1' 'e ekle"
Basic.PropertiesWindow.AddEditableListEntry="Girişi '%1' 'e ekle"
Basic.PropertiesWindow.EditEditableListEntry="'%1' 'den giriş ekle"
+Basic.PropertiesView.FPS.Simple="Basit FPS Değerleri"
+Basic.PropertiesView.FPS.Rational="Rasyonel FPS Değerleri"
+Basic.PropertiesView.FPS.ValidFPSRanges="Geçerli Kare Aralıkları:"
Basic.InteractionWindow="Etkileşime geçilen '%1'"
@@ -200,9 +274,9 @@ Basic.TransformWindow.Alignment.BottomCenter="Alt Orta"
Basic.TransformWindow.Alignment.BottomRight="Sağ alt"
Basic.TransformWindow.BoundsType.None="Sınırsız"
-Basic.TransformWindow.BoundsType.MaxOnly="Yalnızca en büyük boyutu"
-Basic.TransformWindow.BoundsType.ScaleInner="İç sınırlara ölçekle"
-Basic.TransformWindow.BoundsType.ScaleOuter="Dış sınırlara göre boyutlandır"
+Basic.TransformWindow.BoundsType.MaxOnly="Yalnızca maksimum boyut"
+Basic.TransformWindow.BoundsType.ScaleInner="İç sınırlara boyutlandır"
+Basic.TransformWindow.BoundsType.ScaleOuter="Dış sınırlara boyutlandır"
Basic.TransformWindow.BoundsType.ScaleToWidth="Sınır genişliğinde boyutlandır"
Basic.TransformWindow.BoundsType.ScaleToHeight="Sınır yüksekliğinde boyutlandır"
Basic.TransformWindow.BoundsType.Stretch="Sınırlara genişlet"
@@ -214,11 +288,15 @@ Basic.Main.Scenes="Sahneler"
Basic.Main.Sources="Kaynaklar"
Basic.Main.Connecting="Bağlanıyor..."
Basic.Main.StartRecording="Kaydı Başlat"
+Basic.Main.StartReplayBuffer="Tekrar Oynatma Arabelleğini Başlat"
Basic.Main.StartStreaming="Yayını Başlat"
Basic.Main.StopRecording="Kaydı Durdur"
Basic.Main.StoppingRecording="Kayıt Durduruluyor..."
+Basic.Main.StopReplayBuffer="Tekrar Oynatma Arabelleğini Durdur"
+Basic.Main.StoppingReplayBuffer="Tekrar Oynatma Arabelleği Durduruluyor..."
Basic.Main.StopStreaming="Yayını Durdur"
Basic.Main.StoppingStreaming="Canlı Yayın Durduruluyor..."
+Basic.Main.ForceStopStreaming="Yayını Durdur (gecikmeyi yoksay)"
Basic.MainMenu.File="&Dosya"
Basic.MainMenu.File.Export="Dışa Aktar"
@@ -228,6 +306,7 @@ Basic.MainMenu.File.Remux="Re&mux Kayıtları"
Basic.MainMenu.File.Settings="&Ayarlar"
Basic.MainMenu.File.ShowSettingsFolder="Ayarlar Dosyasını Göster"
Basic.MainMenu.File.ShowProfileFolder="Profil Dosyasını Göster"
+Basic.MainMenu.AlwaysOnTop="&Her Zaman Üstte"
Basic.MainMenu.File.Exit="Ç&ıkış"
Basic.MainMenu.Edit="&Düzenle"
@@ -235,8 +314,15 @@ Basic.MainMenu.Edit.Undo="&Geri al"
Basic.MainMenu.Edit.Redo="&Tekrar Yap"
Basic.MainMenu.Edit.UndoAction="&$1 Geri al"
Basic.MainMenu.Edit.RedoAction="&$1 Yinele"
+Basic.MainMenu.Edit.LockPreview="&Önizlemeyi Kilitle"
+Basic.MainMenu.Edit.Scale="Boyutlandırmayı &Önizle"
+Basic.MainMenu.Edit.Scale.Window="Pencereye Boyutlandır"
+Basic.MainMenu.Edit.Scale.Canvas="Tuval (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Çıkış (%1x%2)"
Basic.MainMenu.Edit.Transform="&Dönüştür"
Basic.MainMenu.Edit.Transform.EditTransform="&Dönüştürmeyi Düzenle..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Dönüştürmeyi Kopyala"
+Basic.MainMenu.Edit.Transform.PasteTransform="Dönüştürmeyi Yapıştır"
Basic.MainMenu.Edit.Transform.ResetTransform="&Dönüştürmeyi Sıfırla"
Basic.MainMenu.Edit.Transform.Rotate90CW="90 derece saat yönüne döndür"
Basic.MainMenu.Edit.Transform.Rotate90CCW="90 derece saatin tersi yönüne döndür"
@@ -253,10 +339,22 @@ Basic.MainMenu.Edit.Order.MoveToTop="En &Üste Taşı"
Basic.MainMenu.Edit.Order.MoveToBottom="En &Alta Taşı"
Basic.MainMenu.Edit.AdvAudio="&Gelişmiş Ses Özellikleri"
+Basic.MainMenu.View="&Görünüm"
+Basic.MainMenu.View.Toolbars="&Araç Çubukları"
+Basic.MainMenu.View.Toolbars.Listboxes="&Liste Kutuları"
+Basic.MainMenu.View.SceneTransitions="S&ahne Geçişleri"
+Basic.MainMenu.View.StatusBar="&Durum Çubuğu"
Basic.MainMenu.SceneCollection="&Sahne Koleksiyonu"
Basic.MainMenu.Profile="&Profil"
+Basic.MainMenu.Profile.Import="Profili İçe Aktar"
+Basic.MainMenu.Profile.Export="Profili Dışa Aktar"
+Basic.MainMenu.SceneCollection.Import="Sahne Koleksiyonunu İçe Aktar"
+Basic.MainMenu.SceneCollection.Export="Sahne Koleksiyonunu Dışa Aktar"
+Basic.MainMenu.Profile.Exists="Profil zaten var"
+Basic.MainMenu.SceneCollection.Exists="Sahne koleksiyonu zaten var"
+Basic.MainMenu.Tools="&Araçlar"
Basic.MainMenu.Help="&Yardım"
Basic.MainMenu.Help.Website="&Siteyi Ziyaret Et"
@@ -274,6 +372,25 @@ Basic.Settings.Confirm="Kayıt edilmemiş değişiklikleriniz var. Değişiklikl
Basic.Settings.General="Genel"
Basic.Settings.General.Theme="Tema"
Basic.Settings.General.Language="Dil"
+Basic.Settings.General.EnableAutoUpdates="Başlangıçta güncellemeleri otomatik olarak kontrol et"
+Basic.Settings.General.WarnBeforeStartingStream="Yayın başlatırken onay iletişim kutusunu göster"
+Basic.Settings.General.WarnBeforeStoppingStream="Yayın durduğunda onay iletişim kutusunu göster"
+Basic.Settings.General.Projectors="Projektörler"
+Basic.Settings.General.HideProjectorCursor="Projektörler üzerinde imleci gizle"
+Basic.Settings.General.ProjectorAlwaysOnTop="Projektörleri her zaman üstte tut"
+Basic.Settings.General.Snapping="Kaynak Hizalama"
+Basic.Settings.General.ScreenSnapping="Kaynakları ekranın kenarına yasla"
+Basic.Settings.General.CenterSnapping="Kaynakları dikey ve yatay merkeze yasla"
+Basic.Settings.General.SourceSnapping="Kaynakları diğer kaynaklara yasla"
+Basic.Settings.General.SnapDistance="Yaslama Hassasiyeti"
+Basic.Settings.General.RecordWhenStreaming="Yayın sırasında otomatik olarak kayıt yap"
+Basic.Settings.General.KeepRecordingWhenStreamStops="Yayın durduğunda kaydı tut"
+Basic.Settings.General.ReplayBufferWhileStreaming="Yayın sırasında tekrar oynatma arabelleğini otomatik olarak başlat"
+Basic.Settings.General.KeepReplayBufferStreamStops="Yayın durduğunda tekrar oynatma arabelleğini tut"
+Basic.Settings.General.SysTray="Sistem tepsisi"
+Basic.Settings.General.SysTrayWhenStarted="Başladığında sistem tepsisine küçült"
+Basic.Settings.General.SystemTrayHideMinimize="Her zaman görev çubuğu yerine sistem tepsisine küçült"
+Basic.Settings.General.SaveProjectors="Çıkışta projektörleri kaydet"
Basic.Settings.Stream="Yayın"
Basic.Settings.Stream.StreamType="Yayın Türü"
@@ -283,10 +400,19 @@ Basic.Settings.Output.Format="Kayıt Biçimi"
Basic.Settings.Output.Encoder="Kodlayıcı"
Basic.Settings.Output.SelectDirectory="Kayıt Dizinini Seçin"
Basic.Settings.Output.SelectFile="Kayıt Dosyasını Seçin"
+Basic.Settings.Output.EnforceBitrate="Yayın hizmetini bit hızı sınırlarına zorla"
Basic.Settings.Output.Mode="Çıkış modu"
Basic.Settings.Output.Mode.Simple="Basit"
Basic.Settings.Output.Mode.Adv="Gelişmiş"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg Çıkışı"
+Basic.Settings.Output.UseReplayBuffer="Tekrar Oynatma Arabelleğini Etkinleştir"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Maksimum Yeniden Oynatma Süresi (Seconds)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maksimum Bellek (Megabayt)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Tahmini bellek kullanımı: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Bellek kullanımını tahmin edemezsin. Lütfen maksimum bellek sınırını ayarlayın."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Not: kısayol tuşları bölümünde yeniden oynatma ara belleği için kısayol tuşu ayarladığınızdan emin olun)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Tekrar Oynatma Arabelleği Dosya Adı Öneki"
+Basic.Settings.Output.ReplayBuffer.Suffix="Suffix"
Basic.Settings.Output.Simple.SavePath="Kayıt Yolu"
Basic.Settings.Output.Simple.RecordingQuality="Kayıt Kalitesi"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Canlı Yayın ile Aynı"
@@ -296,31 +422,38 @@ Basic.Settings.Output.Simple.RecordingQuality.Lossless="Kayıpsız Kalite, Çok
Basic.Settings.Output.Simple.Warn.Lossless.Msg="Kayıpsız kalitede kullanmak istediğinizden emin misiniz?"
Basic.Settings.Output.Simple.Warn.Lossless.Title="Kayıpsız kalite uyarısı!"
Basic.Settings.Output.Simple.Encoder.Software="Yazılım (x264)"
+Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Donanım (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Donanım (AMD)"
+Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Donanım (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Yazılım (x264 düşük CPU kullanım önayarı, dosya boyutunu artırır)"
-Basic.Settings.Output.VideoBitrate="Video Bithızı"
-Basic.Settings.Output.AudioBitrate="Ses Bithızı"
+Basic.Settings.Output.VideoBitrate="Video Bit Hızı"
+Basic.Settings.Output.AudioBitrate="Ses Bit Hızı"
Basic.Settings.Output.Reconnect="Otomatik Yeniden Bağlan"
Basic.Settings.Output.RetryDelay="Yeniden Deneme Gecikmesi (saniye)"
-Basic.Settings.Output.MaxRetries="En fazla yeniden deneme sayısı"
+Basic.Settings.Output.MaxRetries="Maksimum Deneme Sayısı"
Basic.Settings.Output.Advanced="Gelişmiş Kodlayıcı Ayarlarını Etkinleştir"
Basic.Settings.Output.EncoderPreset="Kodlayıcı Önayarı (yüksek = daha az İŞLEMCİ)"
Basic.Settings.Output.CustomEncoderSettings="Özel Kodlayıcı Ayarları"
+Basic.Settings.Output.CustomMuxerSettings="Özel Muxer Ayarları"
Basic.Settings.Output.NoSpaceFileName="Dosya ismini boşluk olmadan oluştur"
-Basic.Settings.Output.Adv.Rescale="Çıkışı Yeniden Ölçeklendir"
+Basic.Settings.Output.Adv.Rescale="Çıkışı Yeniden Boyutlandır"
Basic.Settings.Output.Adv.AudioTrack="Ses Parçası"
Basic.Settings.Output.Adv.Streaming="Yayın"
-Basic.Settings.Output.Adv.ApplyServiceSettings="Gerçek zamanlı ayayın hizmeti kodlayıcı ayarlarını zorla"
+Basic.Settings.Output.Adv.ApplyServiceSettings="Yayın hizmetini kodlayıcı ayarlarına zorla"
Basic.Settings.Output.Adv.Audio.Track1="Parça 1"
Basic.Settings.Output.Adv.Audio.Track2="Ses İzi 2"
Basic.Settings.Output.Adv.Audio.Track3="Ses İzi 3"
Basic.Settings.Output.Adv.Audio.Track4="Ses İzi 4"
+Basic.Settings.Output.Adv.Audio.Track5="Parça 5"
+Basic.Settings.Output.Adv.Audio.Track6="Parça 6"
Basic.Settings.Output.Adv.Recording="Kayıt"
Basic.Settings.Output.Adv.Recording.Type="Tür"
Basic.Settings.Output.Adv.Recording.Type.Standard="Standart"
Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Özel Çıkış (FFmpeg)"
Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Yayın kodlayıcı kullan)"
+Basic.Settings.Output.Adv.Recording.Filename="Dosya Adı Biçimi"
Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Dosya varsa üzerine yaz"
Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg Çıkış Türü"
Basic.Settings.Output.Adv.FFmpeg.Type.URL="URL'ye Çıkış"
@@ -341,15 +474,18 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Video Kodlayıcı Ayarları (
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Ses Kodlayıcı"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Ses Kodlayıcı Ayarları (var ise)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer Ayarları (eğer varsa)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Anahtar Kare Aralığı (kare)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Tüm kodekleri göster (potansiyel olarak uyumsuz olsa bile)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
+FilenameFormatting.TT="%CCYY Yıl, dört hane\n%YY Yıl, son iki hane (00-99)\n%MM Ay rakamla (01-12)\n%DD Ayın günü, önü-sıfırlı (01-31)\n%hh Saat 24s formatlı (00-23)\n%mm Dakika (00-59)\n%ss Saniye (00-61)\n%% A % sign\n%a Kısaltılmış gün adı\n%A Tam gün adı\n%b Kısaltılmış ay adı\n%B Tam ay adı\n%d Ayın günü, önü-sıfırlı (01-31)\n%H Saat 24s formatlı (00-23)\n%I Saat 12s formatlı (01-12)\n%m Ay rakamla (01-12)\n%M Dakika (00-59)\n%p AM veya PM belirteci\n%S Saniye (00-61)\n%y Yıl, son iki hane (00-99)\n%Y Yıl\n%z UTC'ye göre ISO 8601 farkı veya zaman dilimi\n adı veya kısaltması\n%Z Zaman dilimi adı veya kısaltması\n"
Basic.Settings.Video="Video"
Basic.Settings.Video.Adapter="Video Bağdaştırıcı:"
Basic.Settings.Video.BaseResolution="Temel (Tuval) Çözünürlüğü:"
-Basic.Settings.Video.ScaledResolution="Çıkış (Ölçekli) Çözünürlüğü:"
-Basic.Settings.Video.DownscaleFilter="Filtreyi Azalt:"
+Basic.Settings.Video.ScaledResolution="Çıkış (Boyutlandırılmış) Çözünürlüğü:"
+Basic.Settings.Video.DownscaleFilter="Boyut Azaltma Filtresi:"
Basic.Settings.Video.DisableAeroWindows="Aero'yu Devre Dışı Bırak (yalnızca Windows)"
Basic.Settings.Video.FPS="FPS:"
Basic.Settings.Video.FPSCommon="Ortak FPS Değerleri"
@@ -362,6 +498,9 @@ Basic.Settings.Video.InvalidResolution="Geçersiz çözünürlük değeri. [Geni
Basic.Settings.Video.CurrentlyActive="Video çıkışı şu anda etkin durumda. Video ayarlarını değiştirmek için lütfen bütün çıkışları kapalı duruma getirin."
Basic.Settings.Video.DisableAero="Aero'yu Devre Dışı Bırak"
+Basic.Settings.Video.DownscaleFilter.Bilinear="Bilinear (En hızlı, ancak boyutlandırmada bulanık görüntü)"
+Basic.Settings.Video.DownscaleFilter.Bicubic="Bicubic (Keskinleştirilmiş boyutlandırma, 16 örnek)"
+Basic.Settings.Video.DownscaleFilter.Lanczos="Lanczos (Keskinleştirilmiş boyutlandırma, 32 örnek)"
Basic.Settings.Audio="Ses"
Basic.Settings.Audio.SampleRate="Örnekleme Sıklığı"
@@ -378,9 +517,11 @@ Basic.Settings.Audio.PushToTalkDelay="Bas-Konuş gecikmesi"
Basic.Settings.Audio.UnknownAudioDevice="[Cihaz bağlı yada kullanılabilir değil]"
Basic.Settings.Advanced="Gelişmiş"
+Basic.Settings.Advanced.General.ProcessPriority="İşlem Önceliği"
Basic.Settings.Advanced.General.ProcessPriority.High="Yüksek"
Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Normalin Üstünde"
Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal"
+Basic.Settings.Advanced.General.ProcessPriority.Idle="Boşta"
Basic.Settings.Advanced.FormatWarning="Uyarı: NV12 dışındaki renk biçimleri esas olarak kayıt için tasarlanmıştır ve yayın anında kullanma önerilmez. Yayın nedeni ile renk biçimini dönüştürme çok fazla İŞLEMCİ kullanımına sebep olabilir."
Basic.Settings.Advanced.Audio.BufferingTime="Ses Ön Bellekleme Süresi"
Basic.Settings.Advanced.Video.ColorFormat="Renk Biçimi"
@@ -388,30 +529,43 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV Renk Alanı"
Basic.Settings.Advanced.Video.ColorRange="YUV Renk Aralığı"
Basic.Settings.Advanced.Video.ColorRange.Partial="Kısmi"
Basic.Settings.Advanced.Video.ColorRange.Full="Tam"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Ses İzleme Aygıtı"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="Varsayılan"
Basic.Settings.Advanced.StreamDelay="Yayın Gecikmesi"
Basic.Settings.Advanced.StreamDelay.Duration="Süre (saniye)"
Basic.Settings.Advanced.StreamDelay.Preserve="Tatbik ederken kesim noktasını (gecikme artışı) koru"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Tahmini Bellek Kullanımı: %1 MB"
+Basic.Settings.Advanced.Network="Ağ"
+Basic.Settings.Advanced.Network.BindToIP="IP Bağla"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Yeni ağ kodunu etkinleştir"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Düşük gecike modu"
Basic.AdvAudio="Gelişmiş Ses Özellikleri"
Basic.AdvAudio.Name="İsim"
Basic.AdvAudio.Volume="Ses Düzeyi (%)"
Basic.AdvAudio.Mono="Mono Karıştırmayı Azalt"
+Basic.AdvAudio.Panning="Kaydırma"
+Basic.AdvAudio.SyncOffset="Eşitleme Uzaklığı (ms)"
+Basic.AdvAudio.Monitoring="Ses İzleme"
+Basic.AdvAudio.Monitoring.None="Ekran Kapalı"
+Basic.AdvAudio.Monitoring.MonitorOnly="Sadece Ekran (sessiz çıkış)"
+Basic.AdvAudio.Monitoring.Both="Ekran ve Çıkış"
Basic.AdvAudio.AudioTracks="Parçalar"
Basic.Settings.Hotkeys="Kısayollar"
+Basic.Settings.Hotkeys.Pair="'%1' ile paylaşılan tuş kombinasyonu açma/kapama olarak çalışır"
-Basic.Hotkeys.StartStreaming="Yayını Başlat"
-Basic.Hotkeys.StopStreaming="Yayını Durdur"
-Basic.Hotkeys.StartRecording="Kaydı Başlat"
-Basic.Hotkeys.StopRecording="Kaydı Durdur"
Basic.Hotkeys.SelectScene="Sahneye geçiş yap"
+Basic.SystemTray.Show="Göster"
+Basic.SystemTray.Hide="Gizle"
+Basic.SystemTray.Message.Reconnecting="Bağlantı kesildi. Yeniden bağlanılıyor..."
Hotkeys.Insert="Ekle"
Hotkeys.Delete="Sil"
Hotkeys.Home="Ana Sayfa"
+Hotkeys.End="End"
Hotkeys.PageUp="Page Up"
Hotkeys.PageDown="Page Down"
Hotkeys.NumLock="Num Lock"
@@ -420,6 +574,7 @@ Hotkeys.CapsLock="Caps Lock"
Hotkeys.Backspace="Backspace"
Hotkeys.Tab="Tab"
Hotkeys.Print="Yazdır"
+Hotkeys.Pause="Duraklat"
Hotkeys.Left="Sol"
Hotkeys.Right="Sağ"
Hotkeys.Up="Yukarı"
@@ -429,6 +584,11 @@ Hotkeys.Super="Süper"
Hotkeys.Menu="Menü"
Hotkeys.Space="Boşluk"
Hotkeys.NumpadNum="Numpad %1"
+Hotkeys.NumpadMultiply="Numpad *"
+Hotkeys.NumpadDivide="Numpad /"
+Hotkeys.NumpadAdd="Numpad Ekle"
+Hotkeys.NumpadSubtract="Numpad -"
+Hotkeys.NumpadDecimal="Numpad ,"
Hotkeys.AppleKeypadNum="%1 (Tuş takımı)"
Hotkeys.AppleKeypadMultiply="* (Tuş takımı)"
Hotkeys.AppleKeypadDivide="/ (Tuş takımı)"
@@ -440,6 +600,7 @@ Hotkeys.MouseButton="%1 Fare"
Mute="Sesi Kapat"
Unmute="Sesi Aç"
+Push-to-mute="Bas-Sessize Al"
Push-to-talk="Bas konuş"
SceneItemShow="'%1' Göster"
@@ -447,4 +608,5 @@ SceneItemHide="'%1' Gizle"
OutputWarnings.NoTracksSelected="En az bir ses parçası seçmelisiniz"
OutputWarnings.MultiTrackRecording="Uyarı: Bazı biçimler (FLV gibi) kayıt başına birden fazla parçayı desteklemez"
+OutputWarnings.MP4Recording="Uyarı: MP4'e kaydedilen kayıtlar eğer dosya sonlandırılamazsa kurtarılamaz (örneğin: Mavi Hata Ekranı, güç kesintisi v.b.). Eğer çoklu ses izi kaydetmek istiyorsanız MKV kullanmayı düşünün ve bittikten sonra sonra kayıtı mp4'e remuxlayabilirsiniz (Dosya->Remux Kayıtları)"
diff --git a/UI/data/locale/uk-UA.ini b/UI/data/locale/uk-UA.ini
index de75835..073f921 100644
--- a/UI/data/locale/uk-UA.ini
+++ b/UI/data/locale/uk-UA.ini
@@ -49,13 +49,33 @@ Right="Зправа"
Top="Зверху"
Bottom="Знизу"
Reset="Скинути"
+Hours="Годин"
+Minutes="Хвилин"
+Seconds="Секунд"
+Deprecated="Припинено підтримку"
+ReplayBuffer="Буфер Повторів"
+Import="Імпорт"
+Export="Експорт"
+
+Updater.Title="Доступне оновлення"
+Updater.Text="Існує нове оновлення:"
+Updater.UpdateNow="Оновити зараз"
+Updater.RemindMeLater="Нагадати пізніше"
+Updater.Skip="Пропустити цю версію"
+Updater.Running.Title="Програма зараз активна"
+Updater.Running.Text="Вивід активний в даний час, будь ласка, завершіть роботу будь-якого активного Виводу перед спробою оновлення"
+Updater.NoUpdatesAvailable.Title="Оновлень немає"
+Updater.NoUpdatesAvailable.Text="На даний час оновлень немає"
+Updater.FailedToLaunch="Не вдалося перевірити оновлення"
+Updater.GameCaptureActive.Title="Захват гри активний"
+Updater.GameCaptureActive.Text="Бібліотека для Захвату гри наразі використовується. Будь ласка, закрийте всі ігри/програми для яких використовувався захват (або перезавантажте Windows) та спробуйте знов."
QuickTransitions.SwapScenes="Поміняти місцями сцени Перегляд/Вивід після Відео-переходу"
QuickTransitions.SwapScenesTT="Міняє місцями сцени Перегляд та Вивід після закінчення Відео-переходу (якщо сцена Вивід ще існує).\nЗміни внесені до обох сцен залишаються."
QuickTransitions.DuplicateScene="Використовувати копію сцени"
QuickTransitions.DuplicateSceneTT="Під час редагування поточної сцени дозволяє зберегти Вивід без змін.\nДля можливості редагувати властивості Джерел, увімкніть також 'Використовувати копію Джерел'.\nЗміна цієї опції призведе до оновлення поточної сцени, яка йде на Вивід (якщо вона ще існує)."
QuickTransitions.EditProperties="Використовувати копію Джерел"
-QuickTransitions.EditPropertiesTT="Під час редагування поточної сцени, дозволяє редагувати властивості Джерел не змінюючи Вивід.\nЦя опція можлива якщо 'Використовувати копію сцени' вибрана.\nДеякі джерела (наприклад медіа або прилади захвату зображень) не підтримують копіювання, тобто не можна внести окремі зміни у джерело.\nЗміна властивостей таких джерел миттєво змінить Вивід (якщо він ще існує).\n\nУвага: Так як джерела внутрішньо копіюються, то це може призвести до додаткового навантаження на систему та використання відео ресурсів."
+QuickTransitions.EditPropertiesTT="Під час редагування поточної сцени, дозволяє редагувати властивості Джерел не змінюючи Вивід.\nЦя опція можлива якщо 'Використовувати копію сцени' вибрана.\nДеякі джерела (наприклад медіа або пристрої захвату зображень) не підтримують копіювання, тобто не можна внести окремі зміни у джерело.\nЗміна властивостей таких джерел миттєво змінить Вивід (якщо він ще існує).\n\nУвага: Так як джерела внутрішньо копіюються, то це може призвести до додаткового навантаження на систему та використання відео ресурсів."
QuickTransitions.HotkeyName="Швидкий відео-перехід: %1"
Basic.AddTransition="Додати Відео-перехід що конфігурується"
@@ -90,6 +110,11 @@ ConfirmRemove.Title="Підтвердження видалення"
ConfirmRemove.Text="Ви дійсно бажаєте видалити \"$1\"?"
ConfirmRemove.TextMultiple="Ви впевнені, що хочете видалити %1 елементів?"
+Output.StartStreamFailed="Не вдалося розпочати трансляцію"
+Output.StartRecordingFailed="Не вдалося розпочати запис"
+Output.StartReplayFailed="Не вдалося запустити Буфер Повторів"
+Output.StartFailedGeneric="Помилка. Вивід не було розпочато. За додатковою інформацією, будь ласка зверніться до файлу журналу.\n\nПримітка: якщо ви використовуєте NVENC або AMD енкодер, перевірте чи оновлений драйвер відео."
+
Output.ConnectFail.Title="Не вдалося підключитися"
Output.ConnectFail.BadPath="Шлях або URL-адреса недосяжні. Будь ласка, перевірте налаштування програмного забезпечення."
Output.ConnectFail.ConnectFailed="Не вдалося підключитися до сервера"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="Недостатньо простору на дис
Output.RecordNoSpace.Msg="На диску недостатньо простору для запису."
Output.RecordError.Title="Помилка запису"
Output.RecordError.Msg="Під час запису відбулася несподівана помилка."
+Output.ReplayBuffer.NoHotkey.Title="Гарячу клавішу не вказано!"
+Output.ReplayBuffer.NoHotkey.Msg="Гарячу клавішу для Буферу Повторів не вказано. Будь ласка, встановіть гарячу клавішу на дію \"Зберегти Повтор\", щоб використовувати її для збереження повторів."
Output.BadPath.Title="Недійсний шлях до файлу"
Output.BadPath.Text="Шлях вказаний для виводу файлу недійсний. Будь ласка, перевірте у налаштуваннях, що шлях було вказано вірно."
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="Спочатку непарні рядки"
Deinterlacing.BottomFieldFirst="Спочатку парні рядки"
+VolControl.SliderUnmuted="Повзунок гучності для '%1': %2"
+VolControl.SliderMuted="Повзунок гучності для '%1': %2 (в даний час звук вимкнено)"
+VolControl.Mute="Вимкнути звук '%1'"
+VolControl.Properties="Властивості для '%1'"
+
Basic.Main.AddSceneDlg.Title="Додати Сцену"
Basic.Main.AddSceneDlg.Text="Будь ласка, введіть назву для Сцени"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="Сцени"
Basic.Main.Sources="Джерела"
Basic.Main.Connecting="З'єднання..."
Basic.Main.StartRecording="Почати запис"
+Basic.Main.StartReplayBuffer="Запустити Буфер Повторів"
Basic.Main.StartStreaming="Почати трансляцію"
Basic.Main.StopRecording="Зупинити запис"
Basic.Main.StoppingRecording="Запис зупиняється..."
+Basic.Main.StopReplayBuffer="Зупинити Буфер Повторів"
+Basic.Main.StoppingReplayBuffer="Буфер Повторів зупиняється..."
Basic.Main.StopStreaming="Закінчити трансляцію"
Basic.Main.StoppingStreaming="Припинення трансляції..."
Basic.Main.ForceStopStreaming="Закінчити трансляцію (миттєво)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="Від&новити"
Basic.MainMenu.Edit.UndoAction="&Відмінити $1"
Basic.MainMenu.Edit.RedoAction="Від&новити $1"
Basic.MainMenu.Edit.LockPreview="&Зафіксувати вікно Перегляду"
+Basic.MainMenu.Edit.Scale="&Масштабувати вікно Перегляду"
+Basic.MainMenu.Edit.Scale.Window="В розмір вікна"
+Basic.MainMenu.Edit.Scale.Canvas="Як Полотно (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="Як Вивід (%1x%2)"
Basic.MainMenu.Edit.Transform="&Розміри"
Basic.MainMenu.Edit.Transform.EditTransform="Редагуват&и Розміри..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Копіювати Розміри"
+Basic.MainMenu.Edit.Transform.PasteTransform="Вставити Розміри"
Basic.MainMenu.Edit.Transform.ResetTransform="Розміри за &замовчуванням"
Basic.MainMenu.Edit.Transform.Rotate90CW="Повернути на 90 За годинниковою стрілкою"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Повернути на 90 Проти годинникової стрілки"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="Панель с&тану"
Basic.MainMenu.SceneCollection="&Набір Сцен"
Basic.MainMenu.Profile="&Профіль"
+Basic.MainMenu.Profile.Import="Імпорт Профілю"
+Basic.MainMenu.Profile.Export="Експорт Профілю"
+Basic.MainMenu.SceneCollection.Import="Імпорт Набору Сцен"
+Basic.MainMenu.SceneCollection.Export="Експорт Набору Сцен"
+Basic.MainMenu.Profile.Exists="Профіль вже існує"
+Basic.MainMenu.SceneCollection.Exists="Набір Сцен вже існує"
Basic.MainMenu.Tools="Додаткові &засоби"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="Є незбережені зміни. Зберегти
Basic.Settings.General="Загальні"
Basic.Settings.General.Theme="Тема"
Basic.Settings.General.Language="Мова"
+Basic.Settings.General.EnableAutoUpdates="Автоматично перевіряти наявність оновлень під час запуску"
Basic.Settings.General.WarnBeforeStartingStream="Показувати підтвердження для початку трансляції"
Basic.Settings.General.WarnBeforeStoppingStream="Показувати підтвердження для закінчення трансляції"
+Basic.Settings.General.Projectors="Проектор"
Basic.Settings.General.HideProjectorCursor="Приховати курсор у режимі Проектор"
Basic.Settings.General.ProjectorAlwaysOnTop="Режим Проектор відображати поверх всіх вікон"
Basic.Settings.General.Snapping="Прив'язка та вирівнювання"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="Примагнітити Джерело
Basic.Settings.General.SnapDistance="Чутливість примагничування"
Basic.Settings.General.RecordWhenStreaming="Автоматично почати запис з початком трансляції"
Basic.Settings.General.KeepRecordingWhenStreamStops="Не припиняти запис, якщо трансляцію закінчено"
-Basic.Settings.General.SysTrayEnabled="Відображати іконку системному треї, та згортати в трей"
+Basic.Settings.General.ReplayBufferWhileStreaming="Автоматично запустити Буфер Повторів з початком трансляції"
+Basic.Settings.General.KeepReplayBufferStreamStops="Не припиняти Буфер Повторів, якщо трансляцію закінчено"
+Basic.Settings.General.SysTray="Системний трей"
Basic.Settings.General.SysTrayWhenStarted="Згорнути програму до трею при запуску"
+Basic.Settings.General.SystemTrayHideMinimize="Згортати в трей замість того, щоб мінімізувати до панелі завдань"
+Basic.Settings.General.SaveProjectors="Зберегти налаштування режиму Проектор при виході"
Basic.Settings.Stream="Трансляція"
Basic.Settings.Stream.StreamType="Тип Трансляції"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="Режим виводу"
Basic.Settings.Output.Mode.Simple="Простий"
Basic.Settings.Output.Mode.Adv="Розширений"
Basic.Settings.Output.Mode.FFmpeg="Вивід FFmpeg"
+Basic.Settings.Output.UseReplayBuffer="Увімкнути Буфер Повторів"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="Максимальна тривалість Повтору (у секундах)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="Максимальний об'єм пам'яті (у мегабайтах)"
+Basic.Settings.Output.ReplayBuffer.Estimate="Буде використано пам'яті: %1 МБ"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Не вдалося оцінити об'єм використання пам'яті. Будь ласка, встановіть максимальний об'єм пам'яті для Буферу Повторів вручну."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Примітка: переконайтеся, що встановили гарячу клавішу для Буферу Повторів в розділі гарячі клавіші)"
+Basic.Settings.Output.ReplayBuffer.Prefix="Буфер Повторів, Ім'я файлу, Префікс"
+Basic.Settings.Output.ReplayBuffer.Suffix="Суфікс"
Basic.Settings.Output.Simple.SavePath="Шлях до запису"
Basic.Settings.Output.Simple.RecordingQuality="Якість запису"
Basic.Settings.Output.Simple.RecordingQuality.Stream="Так само як трансляція"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="Якість Без втрат
Basic.Settings.Output.Simple.Warn.MultipleQSV="Попередження: Не можна використовувати кілька окремих енкодерів QSV одночасно для запису і трансляції. Якщо ви хочете транслювати і записувати одночасно, будь ласка, змінить або енкодер запису, або енкодер трансляції на інший."
Basic.Settings.Output.Simple.Encoder.Software="Програмний (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Апаратний (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Апаратний (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Апаратний (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Програмний (x264, шаблон з низьким завантаженням ЦП, збільшує файл)"
Basic.Settings.Output.VideoBitrate="Відео бітрейт"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="Доріжка 1"
Basic.Settings.Output.Adv.Audio.Track2="Доріжка 2"
Basic.Settings.Output.Adv.Audio.Track3="Доріжка 3"
Basic.Settings.Output.Adv.Audio.Track4="Доріжка 4"
+Basic.Settings.Output.Adv.Audio.Track5="Доріжка 5"
+Basic.Settings.Output.Adv.Audio.Track6="Доріжка 6"
Basic.Settings.Output.Adv.Recording="Запис"
Basic.Settings.Output.Adv.Recording.Type="Тип"
@@ -417,10 +481,12 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Енкодер відео, п
Basic.Settings.Output.Adv.FFmpeg.AEncoder="Енкодер аудіо"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Енкодер аудіо, параметри користувача"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Мультиплексор, параметри користувача"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="Ключові кадри, період (кадрів)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="Показати всі кодеки (навіть якщо потенційно несумісні)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
-FilenameFormatting.TT="%CCYY Рік, чотири цифри\n%YY Рік, останні дві цифри (00-99)\n%MM Місяць за номером (01-12)\n%DD День місяця, ноль попереду (01-31)\n%hh Години у 24-год. форматі (00-23)\n%mm Мінути (00-59)\n%ss Секунди (00-61)\n%% Знак % \n%a Абревіатура дня тижня\n%A День тижня повністю\n%b Абревіатура місяця\n%B Місяць повністю\n%d День місяця, ноль попереду (01-31)\n%H Години у 24-год. форматі (00-23)\n%I Години у 12-год. форматі (01-12)\n%m Місяць за номером (01-12)\n%M Мінути (00-59)\n%p ДП або ПП позначення\n%S Секунди (00-61)\n%y Рік, останні дві цифри (00-99)\n%Y Рік\n%z ISO 8601 поправка від UTC або часовий\n пояс чи абревіатура\n%Z Часовий пояс чи абревіатура\n"
+FilenameFormatting.TT="%CCYY Рік, чотири цифри\n%YY Рік, останні дві цифри (00-99)\n%MM Місяць за номером (01-12)\n%DD День місяця, ноль попереду (01-31)\n%hh Години у 24-год. форматі (00-23)\n%mm Мінути (00-59)\n%ss Секунди (00-61)\n%% Знак % \n%a Абревіатура дня тижня\n%A День тижня повністю\n%b Абревіатура місяця\n%B Місяць повністю\n%d День місяця, ноль попереду (01-31)\n%H Години у 24-год. форматі (00-23)\n%I Години у 12-год. форматі (01-12)\n%m Місяць за номером (01-12)\n%M Мінути (00-59)\n%p ДП або ПП позначення\n%S Секунди (00-61)\n%y Рік, останні дві цифри (00-99)\n%Y Рік\n%z ISO 8601 поправка від UTC або часовий\n пояс чи абревіатура\n%Z Часовий пояс чи абревіатура\n"
Basic.Settings.Video="Відео"
Basic.Settings.Video.Adapter="Відеокарта:"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV, колірний простір"
Basic.Settings.Advanced.Video.ColorRange="YUV, колірний діапазон"
Basic.Settings.Advanced.Video.ColorRange.Partial="Частковий"
Basic.Settings.Advanced.Video.ColorRange.Full="Повний"
+Basic.Settings.Advanced.Audio.MonitoringDevice="Пристрій Тестування Аудіо (на слух)"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="За замовчанням"
Basic.Settings.Advanced.StreamDelay="Затримка трансляції"
Basic.Settings.Advanced.StreamDelay.Duration="Тривалість (секунди)"
Basic.Settings.Advanced.StreamDelay.Preserve="Зберегати точку роз'єднання (збільшує затримку) під час встановлення нового зв'язку"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="Буде використано пам'яті: %1 МБ"
Basic.Settings.Advanced.Network="Мережа"
Basic.Settings.Advanced.Network.BindToIP="Прив'язати до адаптера (IP)"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="Увімкнути новий мережевий код"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="Режим з низькою затримкою"
Basic.AdvAudio="Розширені Налаштування Аудіо"
Basic.AdvAudio.Name="Назва"
@@ -483,15 +553,15 @@ Basic.AdvAudio.Volume="Гучність (%)"
Basic.AdvAudio.Mono="Мікшувати до псевдо-Моно"
Basic.AdvAudio.Panning="Баланс"
Basic.AdvAudio.SyncOffset="Зсув синхронізації (мс)"
+Basic.AdvAudio.Monitoring="Тестування Аудіо (на слух)"
+Basic.AdvAudio.Monitoring.None="Тест вимкнено"
+Basic.AdvAudio.Monitoring.MonitorOnly="Слухати, але не Виводити"
+Basic.AdvAudio.Monitoring.Both="Слухати та Виводити"
Basic.AdvAudio.AudioTracks="Доріжки"
Basic.Settings.Hotkeys="Гарячі клавіші"
Basic.Settings.Hotkeys.Pair="Однакові комбінації клавіш задані до '%1' діють як перемикач"
-Basic.Hotkeys.StartStreaming="Почати трансляцію"
-Basic.Hotkeys.StopStreaming="Закінчити трансляцію"
-Basic.Hotkeys.StartRecording="Почати запис"
-Basic.Hotkeys.StopRecording="Зупинити запис"
Basic.Hotkeys.SelectScene="Перейти до сцени"
Basic.SystemTray.Show="Показати"
@@ -545,4 +615,5 @@ SceneItemHide="Приховати '%1'"
OutputWarnings.NoTracksSelected="Ви повинні вибрати хоча б одну аудіо-доріжку"
OutputWarnings.MultiTrackRecording="Попередження: Певні формати (наприклад, FLV) не підтримують кілька треків на запис"
+OutputWarnings.MP4Recording="Попередження: Запис в MP4 може стати невиправно пошкодженим, якщо файл не буде завершено (наприклад, в результаті BSOD, втрати живлення і т.п.). Якщо ви хочете, мати запис декількох звукових доріжок спробуйте використати MKV та зробіть ремультиплексацію запису до mp4 після того, як запис буде закінчено (Файл->Ремультиплексація Записів)"
diff --git a/UI/data/locale/vi-VN.ini b/UI/data/locale/vi-VN.ini
index 22db6b2..dcd63c8 100644
--- a/UI/data/locale/vi-VN.ini
+++ b/UI/data/locale/vi-VN.ini
@@ -24,7 +24,7 @@ Display="Hiển thị"
Name="Tên"
Exit="Thoát"
Mixer="Bộ trộn"
-Browse="trình duyệt"
+Browse="Chọn đường dẫn"
Mono="Âm thanh đơn"
Stereo="Âm thanh nổi"
DroppedFrames="Khung rớt %1 (%2%)"
@@ -41,18 +41,31 @@ Duplicate="Tạo bản sao"
Enable="Kích hoạt"
DisableOSXVSync="Tắt OSX V-Sync"
ResetOSXVSyncOnExit="Đặt lại OSX V-Sync khi Thoát"
-Transition="Chuyển tiếp"
+HighResourceUsage="Encoder quá tải! Hãy xem xét giảm chất lượng video hoặc sử dụng 1 encoder nhanh hơn."
+Transition="Chuyển cảnh"
QuickTransitions="C. cảnh nhanh"
Left="Trái"
Right="Phải"
Top="Trên"
Bottom="Dưới"
+Reset="Thiết lập lại"
+Hours="Giờ"
+Minutes="Phút"
+Seconds="Giây"
+
QuickTransitions.SwapScenes="Hoán đổi cảnh Xem trước/Đầu ra sau khi Chuyển cảnh"
QuickTransitions.SwapScenesTT="Hoán đổi cảnh xem trước và cảnh đầu ra sau khi chuyển cảnh (nếu cảnh đầu ra gốc vẫn tồn tại).\nMọi thay đổi với cảnh đầu ra gốc sẽ không hoàn tác."
QuickTransitions.DuplicateScene="Tạo bản sao cảnh"
+QuickTransitions.HotkeyName="C. cảnh nhanh: %1"
+Basic.AddTransition="Thêm cấu hình chuyển cảnh"
+Basic.RemoveTransition="Xóa cấu hình chuyển cảnh"
+Basic.TransitionDuration="Thời gian"
+Basic.TogglePreviewProgramMode="Chế độ Studio"
+TransitionNameDlg.Text="Vui lòng nhập tên của cảnh"
+TransitionNameDlg.Title="Tên chuyển cảnh"
TitleBar.Profile="Cấu hình"
TitleBar.Scenes="Cảnh"
@@ -63,18 +76,25 @@ NameExists.Text="Tên hiện đang sử dụng."
NoNameEntered.Title="Vui lòng nhập tên hợp lệ"
NoNameEntered.Text="Bạn không thể sử dụng tên có sản phẩm nào."
+ConfirmStart.Title="Bắt đầu Stream?"
+ConfirmStart.Text="Bạn có chắc muốn bắt đầu stream?"
+ConfirmStop.Title="Ngừng Stream?"
+ConfirmStop.Text="Bạn có chắc muốn dừng stream?"
ConfirmExit.Title="Thoát OBS?"
-ConfirmExit.Text="OBS là hiện đang hoạt động. Tất cả dòng/bản ghi sẽ được đóng cửa. Bạn có chắc bạn muốn thoát khỏi không?"
+ConfirmExit.Text="OBS hiện đang hoạt động. Tất cả các stream/quay video sẽ bị tắt. Bạn có chắc muốn thoát không?"
ConfirmRemove.Title="Xác nhận loại bỏ"
ConfirmRemove.Text="Bạn có chắc bạn muốn loại bỏ '$1' không?"
+ConfirmRemove.TextMultiple="Bạn có chắc bạn muốn xóa %1 nội dung không?"
+
Output.ConnectFail.Title="Không thể kết nối"
Output.ConnectFail.BadPath="URL không hợp lệ của đường dẫn hoặc kết nối. Xin vui lòng kiểm tra cài đặt của bạn để xác nhận rằng họ là hợp lệ."
Output.ConnectFail.ConnectFailed="Không thể kết nối tới hệ phục vụ"
-Output.ConnectFail.Error="Lỗi bất ngờ xảy ra khi thử kết nối tới hệ phục vụ. Biết thêm thông tin trong các tập tin log."
+Output.ConnectFail.InvalidStream="Không thể truy cập kênh chỉ định hoặc khóa stream, Vui lòng kiểm tra khóa stream của bạn. Nếu nó đúng, có thể có một vấn đề về kết nối với máy chủ."
+Output.ConnectFail.Error="1 lỗi bất ngờ xảy ra khi thử kết nối tới máy chủ. Thông tin thêm nằm trong log file."
Output.ConnectFail.Disconnected="Ngắt kết nối từ máy chủ."
Output.RecordFail.Title="Không thể bắt đầu ghi âm"
@@ -100,6 +120,7 @@ LicenseAgreement.Exit="Thoát"
Remux.SourceFile="Ghi âm OBS"
Remux.TargetFile="Tệp đích"
Remux.Remux="Remux"
+Remux.OBSRecording="Ghi OBS"
Remux.FinishedTitle="Remuxing đã hoàn thành"
Remux.Finished="Ghi remuxed"
Remux.FinishedError="Ghi âm remuxed, nhưng các tập tin có thể không đầy đủ"
@@ -125,6 +146,21 @@ Basic.DisplayCapture="Chụp màn hình"
Basic.Main.PreviewConextMenu.Enable="Bật xem trước"
+ScaleFiltering="Scale Filtering"
+ScaleFiltering.Point="Point"
+ScaleFiltering.Bilinear="Bilinear"
+ScaleFiltering.Bicubic="Bicubic"
+ScaleFiltering.Lanczos="Lanczos"
+
+Deinterlacing="Deinterlacing"
+Deinterlacing.Discard="Discard"
+Deinterlacing.Retro="Retro"
+Deinterlacing.Blend="Blend"
+Deinterlacing.Blend2x="Blend 2x"
+Deinterlacing.Linear="Linear"
+Deinterlacing.Linear2x="Linear 2x"
+Deinterlacing.Yadif="Yadif"
+Deinterlacing.Yadif2x="Yadif 2x"
Basic.Main.AddSceneDlg.Title="Thêm cảnh"
@@ -157,7 +193,9 @@ Basic.PropertiesWindow.ConfirmTitle="Thay đổi cài đặt"
Basic.PropertiesWindow.Confirm="Có được lưu thay đổi. Bạn có muốn giữ họ?"
Basic.PropertiesWindow.NoProperties="Không có tài sản có sẵn"
Basic.PropertiesWindow.AddFiles="Thêm tập tin"
+Basic.PropertiesWindow.AddDir="Thêm thư mục"
Basic.PropertiesWindow.AddURL="Thêm đường dẫn/URL"
+Basic.PropertiesWindow.AddEditableListDir="Thêm thư mục vào '%1'"
Basic.PropertiesWindow.AddEditableListFiles="Thêm các tệp vào '%1'"
Basic.PropertiesWindow.AddEditableListEntry="Thêm mục nhập vào '%1'"
Basic.PropertiesWindow.EditEditableListEntry="Chỉnh sửa mục nhập từ '%1'"
@@ -192,6 +230,7 @@ Basic.TransformWindow.Alignment="Vị trí liên kết"
Basic.TransformWindow.BoundsType="Các giáp ranh hộp loại"
Basic.TransformWindow.BoundsAlignment="Liên kết trong các giáp ranh hộp"
Basic.TransformWindow.Bounds="Các giáp ranh hộp kích thước"
+Basic.TransformWindow.Crop="Cắt"
Basic.TransformWindow.Alignment.TopLeft="Góc trên trái"
Basic.TransformWindow.Alignment.TopCenter="Đỉnh Trung tâm"
@@ -217,49 +256,58 @@ Basic.Main.AddSourceHelp.Text="Bạn cần phải có ít nhất 1 cảnh để
Basic.Main.Scenes="Cảnh"
Basic.Main.Sources="Nguồn"
Basic.Main.Connecting="Đang kết nối..."
-Basic.Main.StartRecording="Bắt đầu ghi âm"
+Basic.Main.StartRecording="Bắt đầu ghi"
Basic.Main.StartStreaming="Bắt đầu Streaming"
-Basic.Main.StopRecording="Dừng ghi âm"
+Basic.Main.StopRecording="Dừng ghi"
+Basic.Main.StoppingRecording="Dừng ghi video..."
Basic.Main.StopStreaming="Ngừng Streaming"
+Basic.Main.StoppingStreaming="Dừng stream..."
Basic.Main.ForceStopStreaming="Ngừng Streaming (huỷ chậm trễ)"
Basic.MainMenu.File="&Tập tin"
-Basic.MainMenu.File.Export="&Xuất khẩu"
-Basic.MainMenu.File.Import="&Nhập khẩu"
-Basic.MainMenu.File.ShowRecordings="Bản ghi âm & Hiển thị"
-Basic.MainMenu.File.Remux="Re & mux bản ghi âm"
+Basic.MainMenu.File.Export="&Xuất"
+Basic.MainMenu.File.Import="&Nhập"
+Basic.MainMenu.File.ShowRecordings="Hiển thị &Bản ghi"
+Basic.MainMenu.File.Remux="Re&mux bản ghi"
Basic.MainMenu.File.Settings="&Cài đặt"
-Basic.MainMenu.File.ShowSettingsFolder="Hiển thị cài đặt thư mục"
+Basic.MainMenu.File.ShowSettingsFolder="Hiển thị thư mục cài đặt"
Basic.MainMenu.File.ShowProfileFolder="Hiển thị thư mục hồ sơ"
+Basic.MainMenu.AlwaysOnTop="&Luôn trên đầu trang"
Basic.MainMenu.File.Exit="&Thoát"
-Basic.MainMenu.Edit="& Chỉnh sửa"
-Basic.MainMenu.Edit.Undo="& Hoàn tác"
-Basic.MainMenu.Edit.Redo="& Làm lại"
-Basic.MainMenu.Edit.UndoAction="& Hoàn tác $1"
-Basic.MainMenu.Edit.RedoAction="& Làm lại $1"
-Basic.MainMenu.Edit.Transform="Biến đổi"
-Basic.MainMenu.Edit.Transform.EditTransform="& Chỉnh sửa biến đổi..."
-Basic.MainMenu.Edit.Transform.ResetTransform="& Đặt lại biến đổi"
+Basic.MainMenu.Edit="&Chỉnh sửa"
+Basic.MainMenu.Edit.Undo="&Hoàn tác"
+Basic.MainMenu.Edit.Redo="&Làm lại"
+Basic.MainMenu.Edit.UndoAction="&Hoàn tác $1"
+Basic.MainMenu.Edit.RedoAction="&Làm lại $1"
+Basic.MainMenu.Edit.LockPreview="&Khóa xem trước"
+Basic.MainMenu.Edit.Transform="&Biến đổi"
+Basic.MainMenu.Edit.Transform.EditTransform="&Chỉnh sửa biến đổi..."
+Basic.MainMenu.Edit.Transform.ResetTransform="&Đặt lại biến đổi"
Basic.MainMenu.Edit.Transform.Rotate90CW="Xoay 90 độ bên phải"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Xoay 90 độ bên trái"
Basic.MainMenu.Edit.Transform.Rotate180="Xoay 180 độ"
-Basic.MainMenu.Edit.Transform.FlipHorizontal="Flip & ngang"
-Basic.MainMenu.Edit.Transform.FlipVertical="Flip & dọc"
-Basic.MainMenu.Edit.Transform.FitToScreen="Phù hợp với màn hình"
-Basic.MainMenu.Edit.Transform.StretchToScreen="& Căng để màn hình"
+Basic.MainMenu.Edit.Transform.FlipHorizontal="Lật &Ngang"
+Basic.MainMenu.Edit.Transform.FlipVertical="Lật &Dọc"
+Basic.MainMenu.Edit.Transform.FitToScreen="&Vừa với màn hình"
+Basic.MainMenu.Edit.Transform.StretchToScreen="&Giãn ra để lấp đầy m.hình"
Basic.MainMenu.Edit.Transform.CenterToScreen="& Trung tâm màn hình"
-Basic.MainMenu.Edit.Order="& Đặt hàng"
-Basic.MainMenu.Edit.Order.MoveUp="Chuyển Lên"
-Basic.MainMenu.Edit.Order.MoveDown="Chuyển xuống"
-Basic.MainMenu.Edit.Order.MoveToTop="Chuyển đến đầu trang"
-Basic.MainMenu.Edit.Order.MoveToBottom="Chuyển đến dưới cùng"
-Basic.MainMenu.Edit.AdvAudio="Thuộc tính âm thanh nâng cao"
+Basic.MainMenu.Edit.Order="&Đặt"
+Basic.MainMenu.Edit.Order.MoveUp="Chuyển &Lên"
+Basic.MainMenu.Edit.Order.MoveDown="Chuyển &Xuống"
+Basic.MainMenu.Edit.Order.MoveToTop="Chuyển đến &Đầu"
+Basic.MainMenu.Edit.Order.MoveToBottom="Chuyển xuống &Dưới"
+Basic.MainMenu.Edit.AdvAudio="Các thuộc tính âm thanh nâng cao"
+Basic.MainMenu.View="&Hiển thị"
+Basic.MainMenu.View.Toolbars="&Thanh công cụ"
+Basic.MainMenu.View.Toolbars.Listboxes="&Listboxes"
+Basic.MainMenu.View.StatusBar="&Thanh trạng thái"
-Basic.MainMenu.SceneCollection="& Cảnh bộ sưu tập"
-Basic.MainMenu.Profile="& Hồ sơ"
+Basic.MainMenu.SceneCollection="& Bộ sưu tập cảnh"
+Basic.MainMenu.Profile="&Hồ sơ"
+Basic.MainMenu.Tools="&Công cụ"
Basic.MainMenu.Help="&Trợ giúp"
Basic.MainMenu.Help.Website="Ghé thăm Website"
@@ -277,6 +325,8 @@ Basic.Settings.Confirm="Bạn đã lưu thay đổi. Lưu thay đổi?"
Basic.Settings.General="Chung"
Basic.Settings.General.Theme="Theme"
Basic.Settings.General.Language="Ngôn ngữ"
+Basic.Settings.General.HideProjectorCursor="Ẩn con trỏ chuột trên màn chiếu"
+Basic.Settings.General.ProjectorAlwaysOnTop="Làm cho màn chiếu luôn luôn trên đầu"
Basic.Settings.Stream="Stream"
Basic.Settings.Stream.StreamType="Kiểu Stream"
@@ -301,6 +351,9 @@ Basic.Settings.Output.Simple.Warn.Lossless="Cảnh báo: Lossless chất lượn
Basic.Settings.Output.Simple.Warn.Lossless.Msg="Bạn có chắc bạn muốn sử dụng lossless chất lượng?"
Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless chất lượng cảnh báo!"
Basic.Settings.Output.Simple.Encoder.Software="Phần mềm (x 264)"
+Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Phần cứng (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Phần cứng (AMD)"
+Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Phần cứng (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Phần mềm (x 264 sử dụng CPU thấp cài sẵn, tăng kích thước)"
Basic.Settings.Output.VideoBitrate="Video Bitrate"
Basic.Settings.Output.AudioBitrate="Âm thanh Bitrate"
@@ -327,6 +380,8 @@ Basic.Settings.Output.Adv.Recording.Type="Loại"
Basic.Settings.Output.Adv.Recording.Type.Standard="Chuản"
Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Tùy chỉnh đầu ra (FFmpeg)"
Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Sử dụng dòng mã hóa)"
+Basic.Settings.Output.Adv.Recording.Filename="Định dạng tệp tin"
+Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Ghi đè nếu tập tin tồn tại"
Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg ra loại"
Basic.Settings.Output.Adv.FFmpeg.Type.URL="Sản lượng để URL"
Basic.Settings.Output.Adv.FFmpeg.Type.RecordToFile="Đầu ra vào tập tin"
@@ -374,27 +429,35 @@ Basic.Settings.Audio="Âm thanh"
Basic.Settings.Audio.SampleRate="Tỷ lệ mẫu"
Basic.Settings.Audio.Channels="Kênh Tivi"
Basic.Settings.Audio.DesktopDevice="Thiết bị âm thanh máy tính"
-Basic.Settings.Audio.DesktopDevice2="Thiết bị âm thanh máy tính"
-Basic.Settings.Audio.AuxDevice="Mic/liên minh thiết bị âm thanh"
-Basic.Settings.Audio.AuxDevice2="Mic/liên minh thiết bị âm thanh 2"
-Basic.Settings.Audio.AuxDevice3="Mic/liên minh thiết bị âm thanh 3"
-Basic.Settings.Audio.EnablePushToMute="Sử đẩy để tắt tiếng"
-Basic.Settings.Audio.PushToMuteDelay="Sự chậm trễ đẩy để tắt tiếng"
-Basic.Settings.Audio.EnablePushToTalk="Sử Push-to-talk"
-Basic.Settings.Audio.PushToTalkDelay="Push-to-talk chậm trễ"
+Basic.Settings.Audio.DesktopDevice2="Thiết bị âm thanh máy tính 2"
+Basic.Settings.Audio.AuxDevice="Thiết bị âm thanh mic/phụ trợ"
+Basic.Settings.Audio.AuxDevice2="Thiết bị âm thanh mic/phụ trợ 2"
+Basic.Settings.Audio.AuxDevice3="Thiết bị âm thanh mic/phụ trợ 3"
+Basic.Settings.Audio.EnablePushToMute="Bật bấm để tắt tiếng"
+Basic.Settings.Audio.PushToMuteDelay="Bấm để tắt tiếng trễ"
+Basic.Settings.Audio.EnablePushToTalk="Bật bắm để nói"
+Basic.Settings.Audio.PushToTalkDelay="Bấm để nói trễ"
+Basic.Settings.Audio.UnknownAudioDevice="[Thiết bị không được kết nối hoặc không sẵn dùng]"
Basic.Settings.Advanced="Nâng cao"
-Basic.Settings.Advanced.FormatWarning="Cảnh báo: Định dạng màu sắc khác hơn so với NV12 chủ yếu dành cho ghi âm, và không được khuyến cáo khi streaming. Trực tuyến có thể phải tăng sử dụng CPU do chuyển đổi định dạng màu sắc."
+Basic.Settings.Advanced.General.ProcessPriority="Chương trình ưu tiên"
+Basic.Settings.Advanced.General.ProcessPriority.High="Cao"
+Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Trên bình thường"
+Basic.Settings.Advanced.General.ProcessPriority.Normal="Thường"
+Basic.Settings.Advanced.General.ProcessPriority.Idle="Rảnh"
+Basic.Settings.Advanced.FormatWarning="Cảnh báo: Định dạng màu sắc khác với NV12 chủ yếu dành cho ghi âm và không được khuyến cáo khi streaming. Stream có thể làm tăng sử dụng CPU do phải chuyển đổi định dạng màu sắc."
Basic.Settings.Advanced.Audio.BufferingTime="Âm thanh thời gian đệm"
Basic.Settings.Advanced.Video.ColorFormat="Định dạng màu sắc"
Basic.Settings.Advanced.Video.ColorSpace="Không gian màu YUV"
Basic.Settings.Advanced.Video.ColorRange="Phạm vi màu YUV"
Basic.Settings.Advanced.Video.ColorRange.Partial="Một phần"
Basic.Settings.Advanced.Video.ColorRange.Full="Đầy đủ"
-Basic.Settings.Advanced.StreamDelay="Sự chậm trễ Stream"
-Basic.Settings.Advanced.StreamDelay.Duration="Thời gian (phút)"
-Basic.Settings.Advanced.StreamDelay.Preserve="Bảo tồn cutoff điểm (tăng chậm trễ) khi kết nối lại"
-Basic.Settings.Advanced.StreamDelay.MemoryUsage="Sử dụng ước tính bộ nhớ: %1 MB"
+Basic.Settings.Advanced.StreamDelay="Stream trễ"
+Basic.Settings.Advanced.StreamDelay.Duration="Thời gian (giây)"
+Basic.Settings.Advanced.StreamDelay.Preserve="Giữ điểm cắt (tăng chậm trễ) khi kết nối lại"
+Basic.Settings.Advanced.StreamDelay.MemoryUsage="Ước tính bộ nhớ sử dụng: %1 MB"
+Basic.Settings.Advanced.Network="Mạng"
+Basic.Settings.Advanced.Network.BindToIP="Liên kết với IP"
Basic.AdvAudio="Thuộc tính âm thanh nâng cao"
Basic.AdvAudio.Name="Tên"
@@ -407,13 +470,12 @@ Basic.AdvAudio.AudioTracks="Bài hát"
Basic.Settings.Hotkeys="Phím nóng"
Basic.Settings.Hotkeys.Pair="Tổ hợp phím được chia sẻ với '%1' hành động như chuyển"
-Basic.Hotkeys.StartStreaming="Bắt đầu Streaming"
-Basic.Hotkeys.StopStreaming="Ngừng Streaming"
-Basic.Hotkeys.StartRecording="Bắt đầu ghi âm"
-Basic.Hotkeys.StopRecording="Dừng ghi âm"
Basic.Hotkeys.SelectScene="Chuyển cảnh"
+Basic.SystemTray.Show="Hiện"
+Basic.SystemTray.Hide="Ẩn"
+Basic.SystemTray.Message.Reconnecting="Ngắt kết nối. Đang kết nối lại..."
Hotkeys.Insert="Chèn"
Hotkeys.Delete="Xoá"
@@ -453,12 +515,12 @@ Hotkeys.MouseButton="Chuột %1"
Mute="Tắt Tiếng"
Unmute="Bật tiếng"
-Push-to-mute="Đẩy để tắt tiếng"
-Push-to-talk="Push-to-talk"
+Push-to-mute="Bấm để tắt tiếng"
+Push-to-talk="Bấm để nói"
SceneItemShow="Hiển thị '%1'"
SceneItemHide="Ẩn '%1'"
-OutputWarnings.NoTracksSelected="Bạn phải chọn ít nhất một ca khúc"
-OutputWarnings.MultiTrackRecording="Chú ý: Một số định dạng (chẳng hạn như FLV) không hỗ trợ nhiều bài hát cho một ghi âm"
+OutputWarnings.NoTracksSelected="Bạn phải chọn ít nhất một track"
+OutputWarnings.MultiTrackRecording="Chú ý: Một số định dạng (chẳng hạn như FLV) không hỗ trợ nhiều track cho mỗi video"
diff --git a/UI/data/locale/zh-CN.ini b/UI/data/locale/zh-CN.ini
index 2590603..bc07812 100644
--- a/UI/data/locale/zh-CN.ini
+++ b/UI/data/locale/zh-CN.ini
@@ -49,6 +49,26 @@ Right="右"
Top="上"
Bottom="下"
Reset="重置"
+Hours="小时"
+Minutes="分钟"
+Seconds="秒"
+Deprecated="不推荐使用"
+ReplayBuffer="重拨缓存"
+Import="导入"
+Export="导出"
+
+Updater.Title="有可用的更新"
+Updater.Text="有可用的新版本:"
+Updater.UpdateNow="现在更新"
+Updater.RemindMeLater="稍后再提醒我"
+Updater.Skip="跳过版本"
+Updater.Running.Title="程序当前处于活跃状态"
+Updater.Running.Text="输出当前处于活动状态, 请关闭任何活跃的输出, 然后尝试更新"
+Updater.NoUpdatesAvailable.Title="无可用更新"
+Updater.NoUpdatesAvailable.Text="没有更新当前可用"
+Updater.FailedToLaunch="启动更新程序失败"
+Updater.GameCaptureActive.Title="游戏捕获活跃"
+Updater.GameCaptureActive.Text="游戏捕获钩子库正在使用中, 请关闭所有正在被捕获的游戏/程序(或重新启动 windows), 然后重试."
QuickTransitions.SwapScenes="在过渡动画后交换预览/输出场景"
QuickTransitions.SwapScenesTT="在过渡后,交换预览和输出场景(如果输出的原始场景仍然存在). \n 这个不会撤消任何可能对输出的原始场景的更改."
@@ -90,6 +110,11 @@ ConfirmRemove.Title="确认移除"
ConfirmRemove.Text="确定要删除 '$1' 吗?"
ConfirmRemove.TextMultiple="您确定要删除 %1 项目吗?"
+Output.StartStreamFailed="启动推流失败"
+Output.StartRecordingFailed="启动录像失败"
+Output.StartReplayFailed="启动回放缓存失败"
+Output.StartFailedGeneric="启动输出失败. 请检查日志来了解细节.\n\n注意: 如果你使用的是 NVENC 或 AMD 编码器, 请确保您的视频驱动程序是最新的."
+
Output.ConnectFail.Title="连接失败"
Output.ConnectFail.BadPath="无效的路径或URL。请检查您的设置以确认它们是有效的。"
Output.ConnectFail.ConnectFailed="无法连接到服务器"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="磁盘空间不足"
Output.RecordNoSpace.Msg="没有足够磁盘空间来继续录像."
Output.RecordError.Title="录像错误"
Output.RecordError.Msg="录像时发生未指定错误."
+Output.ReplayBuffer.NoHotkey.Title="没有快捷键设置!"
+Output.ReplayBuffer.NoHotkey.Msg="没有为回放缓存设置快捷键. 请设置保存跨借鉴来用于保存回放录像."
Output.BadPath.Title="错误的文件路径"
Output.BadPath.Text="无效的输出路径。请检查您的设置,确认文件路径是否有效。"
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="上场优先"
Deinterlacing.BottomFieldFirst="下场优先"
+VolControl.SliderUnmuted="音量滑动条 '%1': %2"
+VolControl.SliderMuted="音量滑动条 '%1': %2 (当前静音)"
+VolControl.Mute="静音 '%1'"
+VolControl.Properties="属性 '%1'"
+
Basic.Main.AddSceneDlg.Title="添加场景"
Basic.Main.AddSceneDlg.Text="请输入场景名称"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="场景"
Basic.Main.Sources="来源"
Basic.Main.Connecting="连接中..."
Basic.Main.StartRecording="开始录制"
+Basic.Main.StartReplayBuffer="开始回放缓存"
Basic.Main.StartStreaming="开始串流"
Basic.Main.StopRecording="停止录制"
Basic.Main.StoppingRecording="停止录制..."
+Basic.Main.StopReplayBuffer="停止回放缓存"
+Basic.Main.StoppingReplayBuffer="正在停止回放缓存..."
Basic.Main.StopStreaming="停止串流"
Basic.Main.StoppingStreaming="停止推流..."
Basic.Main.ForceStopStreaming="停止流 (放弃延迟)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="重做 (&R)"
Basic.MainMenu.Edit.UndoAction="撤消 $1 (&U)"
Basic.MainMenu.Edit.RedoAction="重做 $1 (&R)"
Basic.MainMenu.Edit.LockPreview="锁定预览 (&L)"
+Basic.MainMenu.Edit.Scale="预览 & 缩放"
+Basic.MainMenu.Edit.Scale.Window="缩放至窗口"
+Basic.MainMenu.Edit.Scale.Canvas="背景 (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="输出 (%1x%2)"
Basic.MainMenu.Edit.Transform="变换 (&T)"
Basic.MainMenu.Edit.Transform.EditTransform="编辑变换 (&E)"
+Basic.MainMenu.Edit.Transform.CopyTransform="复制变换"
+Basic.MainMenu.Edit.Transform.PasteTransform="粘贴变换"
Basic.MainMenu.Edit.Transform.ResetTransform="重置变换 (&R)"
Basic.MainMenu.Edit.Transform.Rotate90CW="顺时针旋转 90 度(&9)"
Basic.MainMenu.Edit.Transform.Rotate90CCW="逆时针旋转 90 度(&D)"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="状态栏 (&S)"
Basic.MainMenu.SceneCollection="场景集合 (&S)"
Basic.MainMenu.Profile="配置文件 (&P)"
+Basic.MainMenu.Profile.Import="导入配置文件"
+Basic.MainMenu.Profile.Export="导出配置文件"
+Basic.MainMenu.SceneCollection.Import="导入场景集合"
+Basic.MainMenu.SceneCollection.Export="导出场景集合"
+Basic.MainMenu.Profile.Exists="配置文件已存在"
+Basic.MainMenu.SceneCollection.Exists="场景机会已存在"
Basic.MainMenu.Tools="工具 (&T)"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="你有未保存的更改。保存更改吗?"
Basic.Settings.General="通用"
Basic.Settings.General.Theme="主题"
Basic.Settings.General.Language="语言"
+Basic.Settings.General.EnableAutoUpdates="启动时自动检查更新"
Basic.Settings.General.WarnBeforeStartingStream="启动流时显示确认对话框"
Basic.Settings.General.WarnBeforeStoppingStream="停止流时显示确认对话框"
+Basic.Settings.General.Projectors="投影仪"
Basic.Settings.General.HideProjectorCursor="隐藏投影仪上的光标"
Basic.Settings.General.ProjectorAlwaysOnTop="使投影器总是置顶"
Basic.Settings.General.Snapping="源对齐方式"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="对齐源跟其他的源"
Basic.Settings.General.SnapDistance="对齐的敏感性"
Basic.Settings.General.RecordWhenStreaming="当推流时自动录像"
Basic.Settings.General.KeepRecordingWhenStreamStops="当推流停止时保持录像"
-Basic.Settings.General.SysTrayEnabled="启用系统托盘图标"
+Basic.Settings.General.ReplayBufferWhileStreaming="推流时自动启动重播缓冲区"
+Basic.Settings.General.KeepReplayBufferStreamStops="推流停止时重播缓冲区保持活动状态"
+Basic.Settings.General.SysTray="系统托盘"
Basic.Settings.General.SysTrayWhenStarted="开始时最小化到系统托盘"
+Basic.Settings.General.SystemTrayHideMinimize="总是最小化到系统托盘, 而不是任务栏"
+Basic.Settings.General.SaveProjectors="退出时保存投影仪"
Basic.Settings.Stream="串流"
Basic.Settings.Stream.StreamType="串流类型"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="输出模式"
Basic.Settings.Output.Mode.Simple="简单"
Basic.Settings.Output.Mode.Adv="高级"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg 输出"
+Basic.Settings.Output.UseReplayBuffer="启用回放缓存"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="最大回放时间(秒)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="最大内存(Mb)"
+Basic.Settings.Output.ReplayBuffer.Estimate="估计内存使用率: %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="无法估计内存使用率. 请设置最大内存限制."
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(注意: 确保在快捷键部分设置一个回放缓冲区的快捷键)"
+Basic.Settings.Output.ReplayBuffer.Prefix="回放缓存文件名前缀"
+Basic.Settings.Output.ReplayBuffer.Suffix="后缀"
Basic.Settings.Output.Simple.SavePath="录像路径"
Basic.Settings.Output.Simple.RecordingQuality="录像质量"
Basic.Settings.Output.Simple.RecordingQuality.Stream="与流相同"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="无损质量警告!"
Basic.Settings.Output.Simple.Warn.MultipleQSV="警告: 当同时推流和录像时, 你不能使用多个单独的 QSV 编码器. 如果你想要同时推流和录像, 请更改录像的编码器或者推流的编码器."
Basic.Settings.Output.Simple.Encoder.Software="软件 (x264)"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="硬件 (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="硬件 (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="硬件 (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="软件 (x 264 低 CPU 使用率预设,增加文件大小)"
Basic.Settings.Output.VideoBitrate="视频比特率"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="轨道 1"
Basic.Settings.Output.Adv.Audio.Track2="轨道 2"
Basic.Settings.Output.Adv.Audio.Track3="轨道 3"
Basic.Settings.Output.Adv.Audio.Track4="轨道 4"
+Basic.Settings.Output.Adv.Audio.Track5="轨道 5"
+Basic.Settings.Output.Adv.Audio.Track6="轨道 6"
Basic.Settings.Output.Adv.Recording="录像"
Basic.Settings.Output.Adv.Recording.Type="类型"
@@ -417,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="视频编码器设置 (如果
Basic.Settings.Output.Adv.FFmpeg.AEncoder="音频编码器"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="视频编码器设置 (如果有)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer 设置 (如果有)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="关键帧间隔 (帧)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="显示所有编解码器 (即使可能不兼容)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV 颜色空间"
Basic.Settings.Advanced.Video.ColorRange="YUV 颜色范围"
Basic.Settings.Advanced.Video.ColorRange.Partial="局部"
Basic.Settings.Advanced.Video.ColorRange.Full="全部"
+Basic.Settings.Advanced.Audio.MonitoringDevice="音频监测设备"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="默认"
Basic.Settings.Advanced.StreamDelay="流延迟"
Basic.Settings.Advanced.StreamDelay.Duration="持续时间 (秒)"
Basic.Settings.Advanced.StreamDelay.Preserve="重新连接时保持截止点 (增加延迟)"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="估计的内存使用率: %1 MB"
Basic.Settings.Advanced.Network="网络"
Basic.Settings.Advanced.Network.BindToIP="绑定 IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="启用新的网络代码"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="低延迟模式"
Basic.AdvAudio="高级音频属性"
Basic.AdvAudio.Name="名称"
@@ -483,15 +553,15 @@ Basic.AdvAudio.Volume="音量 (%)"
Basic.AdvAudio.Mono="下降混合为单声道"
Basic.AdvAudio.Panning="平移"
Basic.AdvAudio.SyncOffset="同步偏移 (毫秒)"
+Basic.AdvAudio.Monitoring="音频监测"
+Basic.AdvAudio.Monitoring.None="关闭监视"
+Basic.AdvAudio.Monitoring.MonitorOnly="仅显示器(静音输出)"
+Basic.AdvAudio.Monitoring.Both="监视器和输出"
Basic.AdvAudio.AudioTracks="轨道"
Basic.Settings.Hotkeys="热键"
Basic.Settings.Hotkeys.Pair="作为切换的键组合与 '%1' 共享"
-Basic.Hotkeys.StartStreaming="开始串流"
-Basic.Hotkeys.StopStreaming="停止串流"
-Basic.Hotkeys.StartRecording="开始录像"
-Basic.Hotkeys.StopRecording="停止录像"
Basic.Hotkeys.SelectScene="切换到场景"
Basic.SystemTray.Show="显示"
@@ -545,4 +615,5 @@ SceneItemHide="隐藏 '%1'"
OutputWarnings.NoTracksSelected="您必须选择至少一个轨道"
OutputWarnings.MultiTrackRecording="警告: 某些格式 (如 FLV) 不支持每个录像多个轨道"
+OutputWarnings.MP4Recording="警告︰ 录制保存到 MP4 将无法恢复,如果该文件不能完成 (例如由于蓝屏死机,掉电等)。如果您想要记录多个音频轨道考虑使用 MKV 然后在它完成后 remux 录制到 mp4 (文件 -> Remux 录制文件)"
diff --git a/UI/data/locale/zh-TW.ini b/UI/data/locale/zh-TW.ini
index 12e1fd6..674fa19 100644
--- a/UI/data/locale/zh-TW.ini
+++ b/UI/data/locale/zh-TW.ini
@@ -49,6 +49,26 @@ Right="右"
Top="上"
Bottom="下"
Reset="重置"
+Hours="小時"
+Minutes="分鐘"
+Seconds="秒"
+Deprecated="不再維護"
+ReplayBuffer="重播緩衝"
+Import="匯入"
+Export="匯出"
+
+Updater.Title="有新更新"
+Updater.Text="有新更新︰"
+Updater.UpdateNow="立即更新"
+Updater.RemindMeLater="稍後提醒我"
+Updater.Skip="略過此版本"
+Updater.Running.Title="程式處於活動狀態"
+Updater.Running.Text="輸出處於活動狀態,請關閉活動中的輸出,然後再嘗試更新"
+Updater.NoUpdatesAvailable.Title="沒有更新"
+Updater.NoUpdatesAvailable.Text="沒有更新"
+Updater.FailedToLaunch="啟動更新程式失敗"
+Updater.GameCaptureActive.Title="遊戲擷取使用中"
+Updater.GameCaptureActive.Text="遊戲擷取函式庫正在使用中。 請關閉所有被擷取的遊戲/程式 (或重新開機 windows),然後重試。"
QuickTransitions.SwapScenes="轉場後交換預覽/輸出場景"
QuickTransitions.SwapScenesTT="(如果輸出的原始場景仍然存在) 轉場後交換預覽和輸出場景。\n這並不會復原任何對輸出原始場景所作的改動。"
@@ -90,6 +110,11 @@ ConfirmRemove.Title="確認刪除?"
ConfirmRemove.Text="您確定要刪除「$1」?"
ConfirmRemove.TextMultiple="您確定要移除這%1個項目嘛?"
+Output.StartStreamFailed="無法開始串流"
+Output.StartRecordingFailed="無法開始錄影"
+Output.StartReplayFailed="無法啟動重播緩衝區"
+Output.StartFailedGeneric="啟動輸出失敗。 詳情請看 Log 檔。\n\n注意︰ 如果你使用 NVENC 或 AMD 編碼器,請確保您的視頻驅動程式是最新。"
+
Output.ConnectFail.Title="連線失敗"
Output.ConnectFail.BadPath="無效的路徑或 URL。 請確認您的設定是正確的。"
Output.ConnectFail.ConnectFailed="與伺服器連線失敗。"
@@ -103,6 +128,8 @@ Output.RecordNoSpace.Title="硬碟空間不足"
Output.RecordNoSpace.Msg="沒有足夠的空間存放錄製影片"
Output.RecordError.Title="錄製錯誤"
Output.RecordError.Msg="在錄製時發生了預料外的錯誤。"
+Output.ReplayBuffer.NoHotkey.Title="沒有設定熱鍵 !"
+Output.ReplayBuffer.NoHotkey.Msg="沒有為重播緩衝設定儲存重播熱鍵。請設定\"儲存重播\"熱鍵以保存重播。"
Output.BadPath.Title="無效的路徑"
Output.BadPath.Text="無效的輸出路徑。 請確認您的檔案路徑是正確的。"
@@ -164,6 +191,11 @@ Deinterlacing.Yadif2x="Yadif 2x"
Deinterlacing.TopFieldFirst="由偶數場開始"
Deinterlacing.BottomFieldFirst="由奇數場開始"
+VolControl.SliderUnmuted="'%1' 的音量滑桿︰ %2"
+VolControl.SliderMuted="'%1' 的音量滑桿︰ %2 (目前靜音中)"
+VolControl.Mute="靜音 '%1'"
+VolControl.Properties="'%1' 的屬性"
+
Basic.Main.AddSceneDlg.Title="新增場景"
Basic.Main.AddSceneDlg.Text="請輸入場景名稱"
@@ -258,9 +290,12 @@ Basic.Main.Scenes="場景"
Basic.Main.Sources="來源"
Basic.Main.Connecting="連線中……"
Basic.Main.StartRecording="開始錄製"
+Basic.Main.StartReplayBuffer="開始重播緩衝"
Basic.Main.StartStreaming="開始串流"
Basic.Main.StopRecording="停止錄製"
Basic.Main.StoppingRecording="停止錄製..."
+Basic.Main.StopReplayBuffer="停止重播緩衝"
+Basic.Main.StoppingReplayBuffer="正在停止重播緩衝..."
Basic.Main.StopStreaming="停止串流"
Basic.Main.StoppingStreaming="停止串流..."
Basic.Main.ForceStopStreaming="停止實況(丟棄延遲)"
@@ -282,8 +317,14 @@ Basic.MainMenu.Edit.Redo="重做 (&R)"
Basic.MainMenu.Edit.UndoAction="復原 $1 (&U)"
Basic.MainMenu.Edit.RedoAction="重做 $1 (&R)"
Basic.MainMenu.Edit.LockPreview="鎖定預覽 (&L)"
+Basic.MainMenu.Edit.Scale="預覽與縮放"
+Basic.MainMenu.Edit.Scale.Window="縮放至視窗"
+Basic.MainMenu.Edit.Scale.Canvas="畫布 (%1x%2)"
+Basic.MainMenu.Edit.Scale.Output="輸出 (%1x%2)"
Basic.MainMenu.Edit.Transform="變型 (&T)"
Basic.MainMenu.Edit.Transform.EditTransform="編輯變型設定…… (&E)"
+Basic.MainMenu.Edit.Transform.CopyTransform="複製變型"
+Basic.MainMenu.Edit.Transform.PasteTransform="貼上變型"
Basic.MainMenu.Edit.Transform.ResetTransform="重設變型設定 (&R)"
Basic.MainMenu.Edit.Transform.Rotate90CW="順時針旋轉 90°"
Basic.MainMenu.Edit.Transform.Rotate90CCW="逆時針旋轉 90°"
@@ -308,6 +349,12 @@ Basic.MainMenu.View.StatusBar="狀態列(&S)"
Basic.MainMenu.SceneCollection="場景群組 (&S)"
Basic.MainMenu.Profile="設定檔 (&P)"
+Basic.MainMenu.Profile.Import="匯入設定檔"
+Basic.MainMenu.Profile.Export="匯出設定檔"
+Basic.MainMenu.SceneCollection.Import="匯入場景群組"
+Basic.MainMenu.SceneCollection.Export="匯出場景群組"
+Basic.MainMenu.Profile.Exists="已有該設定檔"
+Basic.MainMenu.SceneCollection.Exists="已有該場景群組"
Basic.MainMenu.Tools="工具(&T)"
@@ -327,8 +374,10 @@ Basic.Settings.Confirm="您有未儲存的修改。 是否儲存?"
Basic.Settings.General="一般"
Basic.Settings.General.Theme="佈景主題"
Basic.Settings.General.Language="語言"
+Basic.Settings.General.EnableAutoUpdates="啟動時自動檢查更新"
Basic.Settings.General.WarnBeforeStartingStream="啟動串流時顯示確認對話框"
Basic.Settings.General.WarnBeforeStoppingStream="停止串流時顯示確認對話框"
+Basic.Settings.General.Projectors="投影"
Basic.Settings.General.HideProjectorCursor="當游標在投影上時隱藏游標"
Basic.Settings.General.ProjectorAlwaysOnTop="讓投影總是在最上層"
Basic.Settings.General.Snapping="貼齊對準來源"
@@ -338,8 +387,12 @@ Basic.Settings.General.SourceSnapping="來源與其他來源貼齊"
Basic.Settings.General.SnapDistance="貼齊敏感度"
Basic.Settings.General.RecordWhenStreaming="串流時自動錄製"
Basic.Settings.General.KeepRecordingWhenStreamStops="串流停止時繼續錄製"
-Basic.Settings.General.SysTrayEnabled="啟用系統列圖示"
+Basic.Settings.General.ReplayBufferWhileStreaming="串流時自動啟動重播緩衝"
+Basic.Settings.General.KeepReplayBufferStreamStops="串流停止時依然保持啟用重播緩衝"
+Basic.Settings.General.SysTray="系統工具列"
Basic.Settings.General.SysTrayWhenStarted="開始時最小化至系統列"
+Basic.Settings.General.SystemTrayHideMinimize="總是最小化到系統列,而非工作列"
+Basic.Settings.General.SaveProjectors="退出時保存投影設定"
Basic.Settings.Stream="串流"
Basic.Settings.Stream.StreamType="串流類型"
@@ -354,6 +407,14 @@ Basic.Settings.Output.Mode="輸出模式"
Basic.Settings.Output.Mode.Simple="簡易"
Basic.Settings.Output.Mode.Adv="進階"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg 輸出"
+Basic.Settings.Output.UseReplayBuffer="啟用重播緩衝"
+Basic.Settings.Output.ReplayBuffer.SecondsMax="最大重播時間(秒)"
+Basic.Settings.Output.ReplayBuffer.MegabytesMax="最大記憶體使用量(MB)"
+Basic.Settings.Output.ReplayBuffer.Estimate="估計記憶體使用量︰ %1 MB"
+Basic.Settings.Output.ReplayBuffer.EstimateUnknown="無法預估記憶體使用量。請設定最大記憶體使用量。"
+Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(注意:請確定在熱鍵區有為重播緩衝設定熱鍵)"
+Basic.Settings.Output.ReplayBuffer.Prefix="重播緩衝檔案名稱前綴"
+Basic.Settings.Output.ReplayBuffer.Suffix="後綴"
Basic.Settings.Output.Simple.SavePath="錄影路徑"
Basic.Settings.Output.Simple.RecordingQuality="錄影畫質"
Basic.Settings.Output.Simple.RecordingQuality.Stream="與串流同等畫質"
@@ -369,6 +430,7 @@ Basic.Settings.Output.Simple.Warn.Lossless.Title="無損畫質警告!"
Basic.Settings.Output.Simple.Warn.MultipleQSV="警告︰同時串流和錄影時,不能使用多個不同的 QSV 編碼器。如果你想要在同一時間串流和錄影,請更改錄影編碼器或串流編碼器。"
Basic.Settings.Output.Simple.Encoder.Software="軟體編碼( x264 )"
Basic.Settings.Output.Simple.Encoder.Hardware.QSV="硬體編碼 (QSV)"
+Basic.Settings.Output.Simple.Encoder.Hardware.AMD="硬體 (AMD)"
Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="硬體編碼 (NVENC)"
Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="軟體編碼( x264 預設低 CPU 使用率,將增加檔案容量 )"
Basic.Settings.Output.VideoBitrate="影像位元率(kbit/s)"
@@ -390,6 +452,8 @@ Basic.Settings.Output.Adv.Audio.Track1="音軌 1"
Basic.Settings.Output.Adv.Audio.Track2="音軌 2"
Basic.Settings.Output.Adv.Audio.Track3="音軌 3"
Basic.Settings.Output.Adv.Audio.Track4="音軌 4"
+Basic.Settings.Output.Adv.Audio.Track5="音軌 5"
+Basic.Settings.Output.Adv.Audio.Track6="音軌 6"
Basic.Settings.Output.Adv.Recording="錄影"
Basic.Settings.Output.Adv.Recording.Type="類型"
@@ -417,6 +481,8 @@ Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="影像編碼設定(如果
Basic.Settings.Output.Adv.FFmpeg.AEncoder="音效編碼器"
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="音效編碼設定(如果有才啟用)"
Basic.Settings.Output.Adv.FFmpeg.MuxerSettings="Muxer 設定(如果有才啟用)"
+Basic.Settings.Output.Adv.FFmpeg.GOPSize="關鍵訊框間隔 (訊框)"
+Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat="顯示所有編碼解碼器 (即使可能不相容)"
FilenameFormatting.completer="%CCYY-%MM-%DD %hh-%mm-%ss\n%YY-%MM-%DD %hh-%mm-%ss\n%Y-%m-%d %H-%M-%S\n%y-%m-%d %H-%M-%S\n%a %Y-%m-%d %H-%M-%S\n%A %Y-%m-%d %H-%M-%S\n%Y-%b-%d %H-%M-%S\n%Y-%B-%d %H-%M-%S\n%Y-%m-%d %I-%M-%S-%p\n%Y-%m-%d %H-%M-%S-%z\n%Y-%m-%d %H-%M-%S-%Z"
@@ -470,12 +536,16 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV 色彩空間"
Basic.Settings.Advanced.Video.ColorRange="YUV 顏色範圍"
Basic.Settings.Advanced.Video.ColorRange.Partial="部份"
Basic.Settings.Advanced.Video.ColorRange.Full="完整"
+Basic.Settings.Advanced.Audio.MonitoringDevice="音訊監測設備"
+Basic.Settings.Advanced.Audio.MonitoringDevice.Default="預設裝置"
Basic.Settings.Advanced.StreamDelay="實況延遲"
Basic.Settings.Advanced.StreamDelay.Duration="延遲(秒)"
Basic.Settings.Advanced.StreamDelay.Preserve="重新連線時維持截止點 (增加延遲)"
Basic.Settings.Advanced.StreamDelay.MemoryUsage="預計記憶體使用率: %1 MB"
Basic.Settings.Advanced.Network="網路"
Basic.Settings.Advanced.Network.BindToIP="綁定到 IP"
+Basic.Settings.Advanced.Network.EnableNewSocketLoop="啟用新的網路程式碼"
+Basic.Settings.Advanced.Network.EnableLowLatencyMode="低延遲模式"
Basic.AdvAudio="進階音訊屬性"
Basic.AdvAudio.Name="名稱"
@@ -483,15 +553,15 @@ Basic.AdvAudio.Volume="音量(%)"
Basic.AdvAudio.Mono="混降為單聲道"
Basic.AdvAudio.Panning="偏移"
Basic.AdvAudio.SyncOffset="同步位移(ms)"
+Basic.AdvAudio.Monitoring="音訊監測"
+Basic.AdvAudio.Monitoring.None="關閉監測"
+Basic.AdvAudio.Monitoring.MonitorOnly="僅監測(輸出為靜音)"
+Basic.AdvAudio.Monitoring.Both="監測和輸出"
Basic.AdvAudio.AudioTracks="音軌"
Basic.Settings.Hotkeys="快捷鍵"
Basic.Settings.Hotkeys.Pair="按鍵組合與'%1'共用作為切換鍵"
-Basic.Hotkeys.StartStreaming="開始串流"
-Basic.Hotkeys.StopStreaming="停止串流"
-Basic.Hotkeys.StartRecording="開始錄影"
-Basic.Hotkeys.StopRecording="停止錄影"
Basic.Hotkeys.SelectScene="切換到場景"
Basic.SystemTray.Show="顯示"
@@ -545,4 +615,5 @@ SceneItemHide="隱藏 「%1」"
OutputWarnings.NoTracksSelected="您必須至少選擇一個軌道"
OutputWarnings.MultiTrackRecording="警告:某些格式 (例如 FLV) 不支援多個軌道錄製"
+OutputWarnings.MP4Recording="警告︰ 如果檔案無法完成,儲存成 MP4 的紀錄將無法復原 (例如由於 BSOD,斷電等)。如果想要記錄多個音軌請考慮儲存成 MKV 並在完成後重新封裝成 mp4(檔案 -> 重新封裝)"
diff --git a/UI/display-helpers.hpp b/UI/display-helpers.hpp
index d175932..27ef174 100644
--- a/UI/display-helpers.hpp
+++ b/UI/display-helpers.hpp
@@ -41,6 +41,14 @@ static inline void GetScaleAndCenterPos(
y = windowCY/2 - newCY/2;
}
+static inline void GetCenterPosFromFixedScale(
+ int baseCX, int baseCY, int windowCX, int windowCY,
+ int &x, int &y, float scale)
+{
+ x = (float(windowCX) - float(baseCX)*scale) / 2.0f;
+ y = (float(windowCY) - float(baseCY)*scale) / 2.0f;
+}
+
static inline QSize GetPixelSize(QWidget *widget)
{
return widget->size() * widget->devicePixelRatio();
diff --git a/UI/forms/OBSBasic.ui b/UI/forms/OBSBasic.ui
index 5b922bc..92aa8ed 100644
--- a/UI/forms/OBSBasic.ui
+++ b/UI/forms/OBSBasic.ui
@@ -608,6 +608,9 @@
0
+
+ Transition
+
-
@@ -754,10 +757,16 @@
Basic.TransitionDuration
+
+ transitionDuration
+
-
+
+ Basic.TransitionDuration
+
ms
@@ -850,6 +859,8 @@
Basic.MainMenu.Edit.Transform
+
+
@@ -873,8 +884,17 @@
+
+
@@ -887,6 +907,8 @@
+
+
diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
index ff50261..2d467aa 100644
--- a/UI/forms/OBSBasicSettings.ui
+++ b/UI/forms/OBSBasicSettings.ui
@@ -7,7 +7,7 @@
0
0
981
- 667
+ 748
@@ -116,221 +116,422 @@
0
-
-
- QFormLayout::AllNonFixedFieldsGrow
+
+
+ 0
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ 0
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.General.Language
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- language
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.General.Theme
-
-
- theme
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.General.WarnBeforeStartingStream
-
-
-
- -
-
-
- Basic.Settings.General.WarnBeforeStoppingStream
-
-
-
- -
-
-
- Basic.Settings.General.RecordWhenStreaming
-
-
-
- -
-
-
- Basic.Settings.General.SysTrayEnabled
-
-
-
- -
-
-
- false
-
-
- Basic.Settings.General.SysTrayWhenStarted
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
+
+ 0
+
+
+ 0
+
+ -
+
+
true
-
-
- 0
- 0
-
-
-
- Basic.Settings.General.Snapping
-
-
- false
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ 0
+ 0
+ 818
+ 697
+
- -
-
-
- Enable
-
-
- true
-
-
-
- -
-
-
- Basic.Settings.General.ScreenSnapping
-
-
- true
-
-
-
- -
-
-
- Basic.Settings.General.CenterSnapping
-
-
- true
-
-
-
- -
-
-
- Basic.Settings.General.SourceSnapping
-
-
- true
-
-
-
- -
-
-
- 1
-
-
- 0.500000000000000
-
-
- 10.000000000000000
-
-
-
- -
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.General.SnapDistance
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- -
-
-
- Basic.Settings.General.HideProjectorCursor
-
-
-
- -
-
-
- false
-
-
- Basic.Settings.General.KeepRecordingWhenStreamStops
-
-
-
- -
-
-
- Basic.Settings.General.ProjectorAlwaysOnTop
-
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 9
+
+ -
+
+
+ -
+
+
+ Basic.Settings.General
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 2
+
+ -
+
+
+ Basic.Settings.General.Language
+
+
+ language
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.General.Theme
+
+
+ theme
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.General.EnableAutoUpdates
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 170
+ 5
+
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Output
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ 2
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 170
+ 5
+
+
+
+
+ -
+
+
+ Basic.Settings.General.WarnBeforeStartingStream
+
+
+
+ -
+
+
+ Basic.Settings.General.WarnBeforeStoppingStream
+
+
+
+ -
+
+
+ Basic.Settings.General.RecordWhenStreaming
+
+
+
+ -
+
+
+ false
+
+
+ Basic.Settings.General.KeepRecordingWhenStreamStops
+
+
+
+ -
+
+
+ Basic.Settings.General.ReplayBufferWhileStreaming
+
+
+
+ -
+
+
+ false
+
+
+ Basic.Settings.General.KeepReplayBufferStreamStops
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.General.Snapping
+
+
+ false
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ 2
+
+ -
+
+
+ Enable
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.General.ScreenSnapping
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.General.CenterSnapping
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.General.SourceSnapping
+
+
+ true
+
+
+
+ -
+
+
+ 1
+
+
+ 0.500000000000000
+
+
+ 10.000000000000000
+
+
+
+ -
+
+
+ Basic.Settings.General.SnapDistance
+
+
+ snapDistance
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 170
+ 5
+
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.General.Projectors
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ 2
+
+ -
+
+
+ Basic.Settings.General.HideProjectorCursor
+
+
+
+ -
+
+
+ Basic.Settings.General.ProjectorAlwaysOnTop
+
+
+
+ -
+
+
+ Basic.Settings.General.SaveProjectors
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 170
+ 5
+
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.General.SysTray
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ 2
+
+ -
+
+
+ Enable
+
+
+
+ -
+
+
+ false
+
+
+ Basic.Settings.General.SysTrayWhenStarted
+
+
+
+ -
+
+
+ false
+
+
+ Basic.Settings.General.SystemTrayHideMinimize
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 170
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
@@ -722,7 +923,7 @@
-
-
+
0
@@ -739,6 +940,25 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ -
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.Simple.SavePath
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ simpleOutputPath
+
+
+
-
-
@@ -760,25 +980,6 @@
- -
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.Simple.SavePath
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- simpleOutputPath
-
-
-
-
@@ -789,6 +990,29 @@
+ -
+
+
+ Basic.Settings.Output.Simple.RecordingQuality
+
+
+ simpleOutRecQuality
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Format
+
+
+ simpleOutRecFormat
+
+
+
-
-
@@ -823,32 +1047,6 @@
- -
-
-
- Basic.Settings.Output.Format
-
-
- simpleOutRecFormat
-
-
-
- -
-
-
- -
-
-
- Basic.Settings.Output.Simple.RecordingQuality
-
-
- simpleOutRecQuality
-
-
-
- -
-
-
-
@@ -859,6 +1057,9 @@
+ -
+
+
-
@@ -872,6 +1073,91 @@
-
+ -
+
+
+ Basic.Settings.Output.UseReplayBuffer
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ ReplayBuffer
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.SecondsMax
+
+
+
+ -
+
+
+ sec
+
+
+ 5
+
+
+ 21600
+
+
+ 15
+
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.MegabytesMax
+
+
+
+ -
+
+
+ MB
+
+
+ 20
+
+
+ 8192
+
+
+ 512
+
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.HotkeyMessage
+
+
+
+ -
+
+
+
+
+
+
@@ -1064,6 +1350,20 @@
+ -
+
+
+ 5
+
+
+
+ -
+
+
+ 6
+
+
+
@@ -1407,6 +1707,20 @@
+ -
+
+
+ 5
+
+
+
+ -
+
+
+ 6
+
+
+
@@ -1614,7 +1928,7 @@
- -
+
-
Basic.Settings.Output.VideoBitrate
@@ -1624,7 +1938,7 @@
- -
+
-
0
@@ -1637,7 +1951,27 @@
- -
+
-
+
+
+ 1000000000
+
+
+ 250
+
+
+
+ -
+
+
+ Basic.Settings.Output.Adv.FFmpeg.GOPSize
+
+
+ advOutFFVGOPSize
+
+
+
+ -
@@ -1653,7 +1987,7 @@
- -
+
-
false
@@ -1663,7 +1997,14 @@
- -
+
-
+
+
+ Basic.Settings.Output.Adv.FFmpeg.IgnoreCodecCompat
+
+
+
+ -
Basic.Settings.Output.Adv.FFmpeg.VEncoder
@@ -1673,10 +2014,10 @@
- -
+
-
- -
+
-
Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings
@@ -1686,10 +2027,10 @@
- -
+
-
- -
+
-
Basic.Settings.Output.AudioBitrate
@@ -1699,7 +2040,7 @@
- -
+
-
32
@@ -1715,14 +2056,14 @@
- -
+
-
Basic.Settings.Output.Adv.AudioTrack
- -
+
-
@@ -1774,10 +2115,24 @@
+ -
+
+
+ 5
+
+
+
+ -
+
+
+ 6
+
+
+
- -
+
-
Basic.Settings.Output.Adv.FFmpeg.AEncoder
@@ -1787,10 +2142,10 @@
- -
+
-
- -
+
-
Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings
@@ -1800,7 +2155,7 @@
- -
+
-
-
@@ -2357,6 +2712,236 @@
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Audio.Track5
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ -
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack5Bitrate
+
+
+
+ -
+
+
+ 8
+
+ -
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack5Name
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Audio.Track6
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ -
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ advOutTrack6Bitrate
+
+
+
+ -
+
+
+ 8
+
+ -
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Name
+
+
+ advOutTrack6Name
+
+
+
+ -
+
+
+
+
+
@@ -2545,8 +3130,8 @@
0
0
- 80
- 16
+ 98
+ 28
@@ -2700,10 +3285,10 @@
-
- 30
+ 10
- 3
+ 0
-
@@ -2715,6 +3300,11 @@
20
+ -
+
+ 24 NTSC
+
+
-
29.97
@@ -2911,8 +3501,8 @@
0
0
- 559
- 681
+ 803
+ 738
@@ -2937,6 +3527,9 @@
Basic.Settings.General
+
+ QFormLayout::AllNonFixedFieldsGrow
+
-
@@ -2965,6 +3558,46 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ -
+
+
+ Basic.Settings.Video.Renderer
+
+
+ renderer
+
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Video.Adapter
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+ adapter
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
-
@@ -3008,18 +3641,84 @@
- -
-
-
- Basic.Settings.Advanced.Video.ColorRange
-
-
- colorRange
-
-
-
-
-
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ DisableOSXVSync
+
+
+
+ -
+
+
+ ResetOSXVSyncOnExit
+
+
+
+
+
+ -
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+ -
+
+ 709
+
+
+ -
+
+ 601
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Advanced.Video.ColorRange
+
+
+ colorRange
+
+
+
+ -
+
+
+
-
@@ -3031,73 +3730,30 @@
- -
-
- -
-
- 709
-
-
- -
-
- 601
-
-
-
-
+
+
+
+ -
+
+
+ Basic.Settings.Audio
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
-
-
+
- Basic.Settings.Video.Renderer
+ Basic.Settings.Advanced.Audio.MonitoringDevice
- renderer
+ monitoringDevice
-
-
-
-
-
-
-
- -
-
-
- Basic.Settings.Video.Adapter
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- adapter
-
-
-
- -
-
-
- false
-
-
-
-
-
-
- -
-
-
- DisableOSXVSync
-
-
-
- -
-
-
- ResetOSXVSyncOnExit
-
-
+
@@ -3108,11 +3764,20 @@
Basic.Settings.Output.Adv.Recording
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
-
Basic.Settings.Output.Adv.Recording.Filename
+
+ filenameFormatting
+
-
@@ -3125,6 +3790,48 @@
+ -
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.Suffix
+
+
+ simpleRBSuffix
+
+
+
+ -
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.ReplayBuffer.Prefix
+
+
+ simpleRBPrefix
+
+
+
@@ -3134,16 +3841,12 @@
Basic.Settings.Advanced.StreamDelay
- -
-
-
- Enable
-
-
- true
-
-
-
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ 2
+
-
@@ -3220,6 +3923,16 @@
+ -
+
+
+ Enable
+
+
+ true
+
+
+
@@ -3232,16 +3945,6 @@
QFormLayout::AllNonFixedFieldsGrow
- -
-
-
- Basic.Settings.Output.RetryDelay
-
-
- reconnectRetryDelay
-
-
-
-
@@ -3253,29 +3956,61 @@
-
-
-
- 30
+
+
+ 0
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ 30
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.MaxRetries
+
+
+ reconnectMaxRetries
+
+
+
+ -
+
+
+ 1
+
+
+ 10000
+
+
+
+
- -
-
+ -
+
- Basic.Settings.Output.MaxRetries
+ Basic.Settings.Output.RetryDelay
- reconnectMaxRetries
-
-
-
- -
-
-
- 1
-
-
- 10000
+ reconnectRetryDelay
@@ -3283,7 +4018,7 @@
-
-
+
Basic.Settings.Advanced.Network
@@ -3299,6 +4034,26 @@
Basic.Settings.Advanced.Network.BindToIP
+
+ bindToIP
+
+
+
+ -
+
+
+ Basic.Settings.Advanced.Network.EnableNewSocketLoop
+
+
+
+ -
+
+
+ false
+
+
+ Basic.Settings.Advanced.Network.EnableLowLatencyMode
+
@@ -3354,8 +4109,146 @@
listWidget
- buttonBox
+ streamType
+ outputMode
+ simpleOutputVBitrate
+ simpleOutputABitrate
+ simpleOutAdvanced
+ simpleOutPreset
+ simpleOutCustom
+ simpleOutEnforce
+ simpleOutStrEncoder
+ simpleOutputPath
+ simpleOutputBrowse
+ simpleNoSpace
+ simpleOutRecQuality
+ simpleOutRecFormat
+ simpleOutRecEncoder
+ simpleOutMuxCustom
+ simpleReplayBuf
+ simpleRBSecMax
+ simpleRBMegsMax
+ advOutTabs
+ advOutTrack1
+ advOutTrack2
+ advOutTrack3
+ advOutTrack4
+ advOutTrack5
+ advOutTrack6
+ advOutEncoder
+ advOutApplyService
+ advOutUseRescale
+ advOutRescale
+ advOutRecType
+ advOutRecPath
+ advOutRecPathBrowse
+ advOutNoSpace
+ advOutRecFormat
+ advOutRecTrack1
+ advOutRecTrack2
+ advOutRecTrack3
+ advOutRecTrack4
+ advOutRecTrack5
+ advOutRecTrack6
+ advOutRecEncoder
+ advOutRecUseRescale
+ advOutRecRescale
+ advOutMuxCustom
+ advOutFFRecPath
+ advOutFFPathBrowse
+ advOutFFURL
+ advOutFFFormat
+ advOutFFVBitrate
+ advOutFFVGOPSize
+ advOutFFUseRescale
+ advOutFFRescale
+ advOutFFIgnoreCompat
+ advOutFFVEncoder
+ advOutFFVCfg
+ advOutFFABitrate
+ advOutFFTrack1
+ advOutFFTrack2
+ advOutFFTrack3
+ advOutFFTrack4
+ advOutFFTrack5
+ advOutFFTrack6
+ advOutFFAEncoder
+ advOutFFACfg
+ advOutFFType
+ advOutFFMCfg
+ advOutFFNoSpace
+ advOutTrack1Bitrate
+ advOutTrack1Name
+ advOutTrack2Bitrate
+ advOutTrack2Name
+ advOutTrack3Bitrate
+ advOutTrack3Name
+ advOutTrack4Bitrate
+ advOutTrack4Name
+ advOutTrack5Bitrate
+ advOutTrack5Name
+ advOutTrack6Bitrate
+ advOutTrack6Name
+ sampleRate
+ channelSetup
+ desktopAudioDevice1
+ desktopAudioDevice2
+ auxAudioDevice1
+ auxAudioDevice2
+ auxAudioDevice3
+ audioSourceScrollArea
+ baseResolution
+ outputResolution
+ downscaleFilter
+ fpsType
+ fpsCommon
+ fpsInteger
+ fpsNumerator
+ fpsDenominator
+ scrollArea
+ processPriority
+ renderer
+ adapter
+ colorFormat
+ colorSpace
+ colorRange
+ disableOSXVSync
+ resetOSXVSync
+ monitoringDevice
+ filenameFormatting
+ overwriteIfExists
+ simpleRBPrefix
+ simpleRBSuffix
+ streamDelayEnable
+ streamDelaySec
+ streamDelayPreserve
+ reconnectEnable
+ reconnectRetryDelay
+ reconnectMaxRetries
+ bindToIP
+ enableNewSocketLoop
+ enableLowLatencyMode
+ warnBeforeStreamStop
+ recordWhenStreaming
+ keepRecordStreamStops
+ replayWhileStreaming
+ keepReplayStreamStops
+ snappingEnabled
+ screenSnapping
+ centerSnapping
+ sourceSnapping
+ snapDistance
+ hideProjectorCursor
+ projectorAlwaysOnTop
+ saveProjectors
+ systemTrayEnabled
+ systemTrayWhenStarted
+ systemTrayAlways
+ enableAutoUpdates
+ warnBeforeStreamStart
+ scrollArea_2
language
+ theme
@@ -3384,12 +4277,12 @@
setCurrentIndex(int)
- 310
- 29
+ 159
+ 30
241
- 34
+ 30
@@ -3400,8 +4293,8 @@
setCurrentIndex(int)
- 250
- 39
+ 241
+ 16
250
@@ -3416,12 +4309,12 @@
setVisible(bool)
- 250
- 39
+ 240
+ 46
- 250
- 39
+ 240
+ 44
@@ -3432,12 +4325,12 @@
setVisible(bool)
- 250
- 39
+ 240
+ 46
- 250
- 39
+ 160
+ 44
@@ -3448,12 +4341,12 @@
setVisible(bool)
- 250
- 39
+ 240
+ 46
- 250
- 39
+ 240
+ 43
@@ -3464,12 +4357,12 @@
setVisible(bool)
- 250
- 39
+ 240
+ 46
- 250
- 39
+ 160
+ 43
@@ -3480,12 +4373,12 @@
setCurrentIndex(int)
- 259
- 48
+ 232
+ 41
241
- 30
+ 53
@@ -3496,12 +4389,12 @@
setEnabled(bool)
- 259
- 60
+ 168
+ 67
- 228
- 50
+ 250
+ 67
@@ -3512,12 +4405,12 @@
setEnabled(bool)
- 259
- 39
+ 168
+ 52
- 228
- 29
+ 232
+ 52
@@ -3528,12 +4421,12 @@
setEnabled(bool)
- 259
- 60
+ 168
+ 56
- 228
- 50
+ 232
+ 56
@@ -3544,124 +4437,76 @@
setCurrentIndex(int)
- 259
- 60
+ 250
+ 50
- 259
- 60
+ 250
+ 52
- streamDelayEnable
+ simpleOutAdvanced
toggled(bool)
- label_56
- setEnabled(bool)
+ simpleOutEnforce
+ setVisible(bool)
- 250
- 39
+ 240
+ 46
- 250
- 39
+ 240
+ 45
- streamDelayEnable
+ systemTrayEnabled
toggled(bool)
- streamDelayPreserve
+ systemTrayWhenStarted
setEnabled(bool)
- 250
- 39
+ 730
+ 556
- 250
- 39
+ 746
+ 579
- streamDelayEnable
+ systemTrayEnabled
toggled(bool)
- widget_12
+ systemTrayAlways
setEnabled(bool)
- 250
- 39
+ 830
+ 556
- 250
- 39
+ 826
+ 602
- reconnectEnable
+ enableNewSocketLoop
toggled(bool)
- label_17
+ enableLowLatencyMode
setEnabled(bool)
- 250
- 39
+ 403
+ 642
- 250
- 39
-
-
-
-
- reconnectEnable
- toggled(bool)
- reconnectRetryDelay
- setEnabled(bool)
-
-
- 250
- 39
-
-
- 250
- 39
-
-
-
-
- reconnectEnable
- toggled(bool)
- label_22
- setEnabled(bool)
-
-
- 250
- 39
-
-
- 250
- 39
-
-
-
-
- reconnectEnable
- toggled(bool)
- reconnectMaxRetries
- setEnabled(bool)
-
-
- 250
- 39
-
-
- 250
- 39
+ 403
+ 665
@@ -3672,12 +4517,12 @@
setEnabled(bool)
- 720
- 280
+ 733
+ 317
- 346
- 306
+ 347
+ 343
@@ -3688,12 +4533,12 @@
setEnabled(bool)
- 761
- 280
+ 774
+ 317
- 778
- 306
+ 782
+ 343
@@ -3705,11 +4550,11 @@
820
- 280
+ 317
- 810
- 329
+ 837
+ 366
@@ -3720,12 +4565,12 @@
setEnabled(bool)
- 862
- 280
+ 881
+ 317
- 859
- 352
+ 890
+ 389
@@ -3736,28 +4581,12 @@
setEnabled(bool)
- 866
- 280
+ 928
+ 317
- 866
- 375
-
-
-
-
- simpleOutAdvanced
- toggled(bool)
- simpleOutEnforce
- setVisible(bool)
-
-
- 250
- 39
-
-
- 250
- 39
+ 915
+ 412
@@ -3768,28 +4597,92 @@
setEnabled(bool)
- 404
- 193
+ 803
+ 199
- 404
- 219
+ 820
+ 222
- systemTrayEnabled
+ replayWhileStreaming
toggled(bool)
- systemTrayWhenStarted
+ keepReplayStreamStops
setEnabled(bool)
- 404
+ 747
245
- 404
- 271
+ 753
+ 268
+
+
+
+
+ streamDelayEnable
+ toggled(bool)
+ label_56
+ setEnabled(bool)
+
+
+ 431
+ 422
+
+
+ 356
+ 443
+
+
+
+
+ streamDelayEnable
+ toggled(bool)
+ streamDelaySec
+ setEnabled(bool)
+
+
+ 465
+ 420
+
+
+ 463
+ 447
+
+
+
+
+ streamDelayEnable
+ toggled(bool)
+ streamDelayInfo
+ setEnabled(bool)
+
+
+ 533
+ 420
+
+
+ 557
+ 446
+
+
+
+
+ streamDelayEnable
+ toggled(bool)
+ streamDelayPreserve
+ setEnabled(bool)
+
+
+ 504
+ 420
+
+
+ 494
+ 465
diff --git a/UI/forms/OBSBasicTransform.ui b/UI/forms/OBSBasicTransform.ui
index c801b3d..971cd02 100644
--- a/UI/forms/OBSBasicTransform.ui
+++ b/UI/forms/OBSBasicTransform.ui
@@ -493,6 +493,25 @@
-
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 70
+ 0
+
+
+
+ 100000
+
+
+
-
@@ -602,25 +621,6 @@
- -
-
-
-
- 0
- 0
-
-
-
-
- 70
- 0
-
-
-
- 100000
-
-
-
-
@@ -648,5 +648,12 @@
-
+
+
+ buttonBox
+ rejected()
+ OBSBasicTransform
+ reject()
+
+
diff --git a/UI/forms/OBSUpdate.ui b/UI/forms/OBSUpdate.ui
new file mode 100644
index 0000000..f7a77e9
--- /dev/null
+++ b/UI/forms/OBSUpdate.ui
@@ -0,0 +1,103 @@
+
+
+ OBSUpdate
+
+
+
+ 0
+ 0
+ 611
+ 526
+
+
+
+ Updater.Title
+
+
+ -
+
+
+ Updater.Text
+
+
+
+ -
+
+
+ true
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p></body></html>
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Updater.UpdateNow
+
+
+ true
+
+
+
+ -
+
+
+ Updater.RemindMeLater
+
+
+
+ -
+
+
+ Updater.Skip
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UI/forms/images/obs.png b/UI/forms/images/obs.png
old mode 100644
new mode 100755
index 9a6a8cc..e187877
Binary files a/UI/forms/images/obs.png and b/UI/forms/images/obs.png differ
diff --git a/UI/forms/images/tray_active.png b/UI/forms/images/tray_active.png
old mode 100644
new mode 100755
index d8da1c5..4f6a012
Binary files a/UI/forms/images/tray_active.png and b/UI/forms/images/tray_active.png differ
diff --git a/UI/frontend-plugins/CMakeLists.txt b/UI/frontend-plugins/CMakeLists.txt
index 0a90a60..bd2d336 100644
--- a/UI/frontend-plugins/CMakeLists.txt
+++ b/UI/frontend-plugins/CMakeLists.txt
@@ -1,3 +1 @@
-if(WIN32 OR APPLE)
- add_subdirectory(frontend-tools)
-endif()
+add_subdirectory(frontend-tools)
diff --git a/UI/frontend-plugins/frontend-tools/CMakeLists.txt b/UI/frontend-plugins/frontend-tools/CMakeLists.txt
index b15dc52..5586495 100644
--- a/UI/frontend-plugins/frontend-tools/CMakeLists.txt
+++ b/UI/frontend-plugins/frontend-tools/CMakeLists.txt
@@ -5,20 +5,53 @@ if(APPLE)
include_directories(${COCOA})
endif()
+if(WIN32 OR APPLE)
+ set(frontend-tools_HEADERS
+ auto-scene-switcher.hpp
+ )
+ set(frontend-tools_SOURCES
+ auto-scene-switcher.cpp
+ )
+ set(frontend-tools_UI
+ forms/auto-scene-switcher.ui
+ )
+endif()
+
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/frontend-tools-config.h.in"
+ "${CMAKE_BINARY_DIR}/config/frontend-tools-config.h")
+
set(frontend-tools_HEADERS
- auto-scene-switcher.hpp
+ ${frontend-tools_HEADERS}
+ "${CMAKE_BINARY_DIR}/config/frontend-tools-config.h"
+ output-timer.hpp
+ tool-helpers.hpp
)
set(frontend-tools_SOURCES
+ ${frontend-tools_SOURCES}
frontend-tools.c
- auto-scene-switcher.cpp
+ output-timer.cpp
)
set(frontend-tools_UI
- forms/auto-scene-switcher.ui
+ ${frontend-tools_UI}
+ forms/output-timer.ui
)
if(WIN32)
set(frontend-tools_PLATFORM_SOURCES
auto-scene-switcher-win.cpp)
+
+ if(BUILD_CAPTIONS)
+ set(frontend-tools_PLATFORM_SOURCES
+ ${frontend-tools_PLATFORM_SOURCES}
+ captions.cpp
+ captions-stream.cpp)
+ set(frontend-tools_PLATFORM_HEADERS
+ captions.hpp
+ captions-stream.hpp)
+ set(frontend-tools_PLATFORM_UI
+ forms/captions.ui)
+ endif()
elseif(APPLE)
set(frontend-tools_PLATFORM_SOURCES
auto-scene-switcher-osx.mm)
@@ -29,13 +62,16 @@ elseif(APPLE)
${COCOA})
endif()
-qt5_wrap_ui(frontend-tools_UI_HEADERS ${frontend-tools_UI})
+qt5_wrap_ui(frontend-tools_UI_HEADERS
+ ${frontend-tools_UI}
+ ${frontend-tools_PLATFORM_UI})
add_library(frontend-tools MODULE
${frontend-tools_HEADERS}
${frontend-tools_SOURCES}
- ${frontend-tools_PLATFORM_SOURCES}
${frontend-tools_UI_HEADERS}
+ ${frontend-tools_PLATFORM_SOURCES}
+ ${frontend-tools_PLATFORM_HEADERS}
)
target_link_libraries(frontend-tools
${frontend-tools_PLATFORM_LIBS}
diff --git a/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp b/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp
index 9c737bf..06c0307 100644
--- a/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp
+++ b/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp
@@ -3,8 +3,10 @@
#include
#include
#include
+#include
#include
#include "auto-scene-switcher.hpp"
+#include "tool-helpers.hpp"
#include
#include
@@ -81,37 +83,6 @@ static inline QString MakeSwitchName(const QString &scene,
return QStringLiteral("[") + scene + QStringLiteral("]: ") + window;
}
-static inline string GetWeakSourceName(obs_weak_source_t *weak_source)
-{
- string name;
-
- obs_source_t *source = obs_weak_source_get_source(weak_source);
- if (source) {
- name = obs_source_get_name(source);
- obs_source_release(source);
- }
-
- return name;
-}
-
-static inline OBSWeakSource GetWeakSourceByName(const char *name)
-{
- OBSWeakSource weak;
- obs_source_t *source = obs_get_source_by_name(name);
- if (source) {
- weak = obs_source_get_weak_source(source);
- obs_weak_source_release(weak);
- obs_source_release(source);
- }
-
- return weak;
-}
-
-static inline OBSWeakSource GetWeakSourceByQString(const QString &name)
-{
- return GetWeakSourceByName(name.toUtf8().constData());
-}
-
SceneSwitcher::SceneSwitcher(QWidget *parent)
: QDialog(parent),
ui(new Ui_SceneSwitcher)
@@ -231,13 +202,19 @@ void SceneSwitcher::on_add_clicked()
int idx = FindByData(windowName);
if (idx == -1) {
- QListWidgetItem *item = new QListWidgetItem(text,
- ui->switches);
- item->setData(Qt::UserRole, v);
-
- lock_guard lock(switcher->m);
- switcher->switches.emplace_back(source,
- windowName.toUtf8().constData());
+ try {
+ lock_guard lock(switcher->m);
+ switcher->switches.emplace_back(source,
+ windowName.toUtf8().constData());
+
+ QListWidgetItem *item = new QListWidgetItem(text,
+ ui->switches);
+ item->setData(Qt::UserRole, v);
+ } catch (const regex_error &) {
+ QMessageBox::warning(this,
+ obs_module_text("InvalidRegex.Title"),
+ obs_module_text("InvalidRegex.Text"));
+ }
} else {
QListWidgetItem *item = ui->switches->item(idx);
item->setText(text);
diff --git a/UI/frontend-plugins/frontend-tools/captions-stream.cpp b/UI/frontend-plugins/frontend-tools/captions-stream.cpp
new file mode 100644
index 0000000..b983bad
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/captions-stream.cpp
@@ -0,0 +1,418 @@
+#include "captions-stream.hpp"
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+#if 0
+#define debugfunc(format, ...) blog(LOG_DEBUG, "[Captions] %s(" format ")", \
+ __FUNCTION__, ##__VA_ARGS__)
+#else
+#define debugfunc(format, ...)
+#endif
+
+CaptionStream::CaptionStream(DWORD samplerate_) :
+ samplerate(samplerate_),
+ event(CreateEvent(nullptr, false, false, nullptr))
+{
+ buf_info.ulMsMinNotification = 50;
+ buf_info.ulMsBufferSize = 500;
+ buf_info.ulMsEventBias = 0;
+
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = 1;
+ format.nSamplesPerSec = 16000;
+ format.nAvgBytesPerSec = format.nSamplesPerSec * sizeof(uint16_t);
+ format.nBlockAlign = 2;
+ format.wBitsPerSample = 16;
+ format.cbSize = sizeof(format);
+
+ resampler.Reset(&format);
+}
+
+void CaptionStream::Stop()
+{
+ {
+ lock_guard lock(m);
+ circlebuf_free(buf);
+ }
+
+ cv.notify_one();
+}
+
+void CaptionStream::PushAudio(const struct audio_data *data, bool muted)
+{
+ uint8_t *output[MAX_AV_PLANES] = {};
+ uint32_t frames = data->frames;
+ uint64_t ts_offset;
+ bool ready = false;
+
+ audio_resampler_resample(resampler, output, &frames, &ts_offset,
+ data->data, data->frames);
+
+ if (output[0]) {
+ if (muted)
+ memset(output[0], 0, frames * sizeof(int16_t));
+
+ lock_guard lock(m);
+ circlebuf_push_back(buf, output[0], frames * sizeof(int16_t));
+ write_pos += frames * sizeof(int16_t);
+
+ if (wait_size && buf->size >= wait_size)
+ ready = true;
+ }
+
+ if (ready)
+ cv.notify_one();
+}
+
+// IUnknown methods
+
+STDMETHODIMP CaptionStream::QueryInterface(REFIID riid, void **ppv)
+{
+ if (riid == IID_IUnknown) {
+ AddRef();
+ *ppv = this;
+
+ } else if (riid == IID_IStream) {
+ AddRef();
+ *ppv = (IStream*)this;
+
+ } else if (riid == IID_ISpStreamFormat) {
+ AddRef();
+ *ppv = (ISpStreamFormat*)this;
+
+ } else if (riid == IID_ISpAudio) {
+ AddRef();
+ *ppv = (ISpAudio*)this;
+
+ } else {
+ *ppv = nullptr;
+ return E_NOINTERFACE;
+ }
+
+ return NOERROR;
+}
+
+STDMETHODIMP_(ULONG) CaptionStream::AddRef()
+{
+ return (ULONG)os_atomic_inc_long(&refs);
+}
+
+STDMETHODIMP_(ULONG) CaptionStream::Release()
+{
+ ULONG new_refs = (ULONG)os_atomic_dec_long(&refs);
+ if (!new_refs)
+ delete this;
+
+ return new_refs;
+}
+
+// ISequentialStream methods
+
+STDMETHODIMP CaptionStream::Read(void *data, ULONG bytes, ULONG *read_bytes)
+{
+ HRESULT hr = S_OK;
+ size_t cur_size;
+
+ debugfunc("data, %lu, read_bytes", bytes);
+ if (!data)
+ return STG_E_INVALIDPOINTER;
+
+ {
+ lock_guard lock1(m);
+ wait_size = bytes;
+ cur_size = buf->size;
+ }
+
+ unique_lock lock(m);
+
+ if (bytes > cur_size)
+ cv.wait(lock);
+
+ if (bytes > (ULONG)buf->size) {
+ bytes = (ULONG)buf->size;
+ hr = S_FALSE;
+ }
+ if (bytes)
+ circlebuf_pop_front(buf, data, bytes);
+ if (read_bytes)
+ *read_bytes = bytes;
+
+ wait_size = 0;
+ pos.QuadPart += bytes;
+ return hr;
+}
+
+STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes,
+ ULONG*)
+{
+ debugfunc("data, %lu, written_bytes", bytes);
+ UNUSED_PARAMETER(bytes);
+
+ return STG_E_INVALIDFUNCTION;
+}
+
+// IStream methods
+
+STDMETHODIMP CaptionStream::Seek(LARGE_INTEGER move, DWORD origin,
+ ULARGE_INTEGER *new_pos)
+{
+ debugfunc("%lld, %lx, new_pos", move, origin);
+ UNUSED_PARAMETER(move);
+ UNUSED_PARAMETER(origin);
+
+ if (!new_pos)
+ return E_POINTER;
+
+ if (origin != SEEK_CUR || move.QuadPart != 0)
+ return E_NOTIMPL;
+
+ *new_pos = pos;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::SetSize(ULARGE_INTEGER new_size)
+{
+ debugfunc("%llu", new_size);
+ UNUSED_PARAMETER(new_size);
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CaptionStream::CopyTo(IStream *stream, ULARGE_INTEGER bytes,
+ ULARGE_INTEGER *read_bytes,
+ ULARGE_INTEGER *written_bytes)
+{
+ HRESULT hr;
+
+ debugfunc("stream, %llu, read_bytes, written_bytes", bytes);
+
+ if (!stream)
+ return STG_E_INVALIDPOINTER;
+
+ ULONG written = 0;
+ if (bytes.QuadPart > (ULONGLONG)buf->size)
+ bytes.QuadPart = (ULONGLONG)buf->size;
+
+ lock_guard lock(m);
+ temp_buf.resize((size_t)bytes.QuadPart);
+ circlebuf_peek_front(buf, &temp_buf[0], (size_t)bytes.QuadPart);
+
+ hr = stream->Write(temp_buf.data(), (ULONG)bytes.QuadPart, &written);
+
+ if (read_bytes)
+ *read_bytes = bytes;
+ if (written_bytes)
+ written_bytes->QuadPart = written;
+
+ return hr;
+}
+
+STDMETHODIMP CaptionStream::Commit(DWORD commit_flags)
+{
+ debugfunc("%lx", commit_flags);
+ UNUSED_PARAMETER(commit_flags);
+ /* TODO? */
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::Revert(void)
+{
+ debugfunc("");
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset,
+ ULARGE_INTEGER size, DWORD type)
+{
+ debugfunc("%llu, %llu, %ld", offset, size, type);
+ UNUSED_PARAMETER(offset);
+ UNUSED_PARAMETER(size);
+ UNUSED_PARAMETER(type);
+ /* TODO? */
+ return STG_E_INVALIDFUNCTION;
+}
+
+STDMETHODIMP CaptionStream::UnlockRegion(ULARGE_INTEGER offset,
+ ULARGE_INTEGER size, DWORD type)
+{
+ debugfunc("%llu, %llu, %ld", offset, size, type);
+ UNUSED_PARAMETER(offset);
+ UNUSED_PARAMETER(size);
+ UNUSED_PARAMETER(type);
+ /* TODO? */
+ return STG_E_INVALIDFUNCTION;
+}
+
+static const wchar_t *stat_name = L"Caption stream";
+
+STDMETHODIMP CaptionStream::Stat(STATSTG *stg, DWORD flag)
+{
+ debugfunc("stg, %lu", flag);
+
+ if (!stg)
+ return E_POINTER;
+
+ lock_guard lock(m);
+ *stg = {};
+ stg->type = STGTY_STREAM;
+ stg->cbSize.QuadPart = (ULONGLONG)buf->size;
+
+ if (flag == STATFLAG_DEFAULT) {
+ stg->pwcsName = (wchar_t*)CoTaskMemAlloc(sizeof(stat_name));
+ memcpy(stg->pwcsName, stat_name, sizeof(stat_name));
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::Clone(IStream **stream)
+{
+ debugfunc("stream");
+ *stream = nullptr;
+ return E_NOTIMPL;
+}
+
+// ISpStreamFormat methods
+
+STDMETHODIMP CaptionStream::GetFormat(GUID *guid,
+ WAVEFORMATEX **co_mem_wfex_out)
+{
+ debugfunc("guid, co_mem_wfex_out");
+
+ if (!guid || !co_mem_wfex_out)
+ return E_POINTER;
+
+ if (format.wFormatTag == 0) {
+ *co_mem_wfex_out = nullptr;
+ return S_OK;
+ }
+
+ void *wfex = CoTaskMemAlloc(sizeof(format));
+ memcpy(wfex, &format, sizeof(format));
+
+ *co_mem_wfex_out = (WAVEFORMATEX*)wfex;
+ return S_OK;
+}
+
+// ISpAudio methods
+
+STDMETHODIMP CaptionStream::SetState(SPAUDIOSTATE state_, ULONGLONG)
+{
+ debugfunc("%lu, reserved", state_);
+ state = state_;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref,
+ const WAVEFORMATEX *wfex)
+{
+ debugfunc("guid, wfex");
+ if (!wfex)
+ return E_INVALIDARG;
+
+ if (guid_ref == SPDFID_WaveFormatEx) {
+ lock_guard lock(m);
+ memcpy(&format, wfex, sizeof(format));
+ resampler.Reset(wfex);
+
+ /* 50 msec */
+ DWORD size = format.nSamplesPerSec / 20;
+ DWORD byte_size = size * format.nBlockAlign;
+ circlebuf_reserve(buf, (size_t)byte_size);
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::GetStatus(SPAUDIOSTATUS *status)
+{
+ debugfunc("status");
+
+ if (!status)
+ return E_POINTER;
+
+ /* TODO? */
+ lock_guard lock(m);
+ *status = {};
+ status->cbNonBlockingIO = (ULONG)buf->size;
+ status->State = state;
+ status->CurSeekPos = pos.QuadPart;
+ status->CurDevicePos = write_pos;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info_)
+{
+ debugfunc("buf_info");
+
+ /* TODO */
+ buf_info = *buf_info_;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::GetBufferInfo(SPAUDIOBUFFERINFO *buf_info_)
+{
+ debugfunc("buf_info");
+ if (!buf_info_)
+ return E_POINTER;
+
+ *buf_info_ = buf_info;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format,
+ WAVEFORMATEX **co_mem_wfex_out)
+{
+ debugfunc("format, co_mem_wfex_out");
+
+ if (!format || !co_mem_wfex_out)
+ return E_POINTER;
+
+ void *wfex = CoTaskMemAlloc(sizeof(format));
+ memcpy(wfex, &format, sizeof(format));
+
+ *format = SPDFID_WaveFormatEx;
+ *co_mem_wfex_out = (WAVEFORMATEX*)wfex;
+ return S_OK;
+}
+
+STDMETHODIMP_(HANDLE) CaptionStream::EventHandle(void)
+{
+ debugfunc("");
+ return event;
+}
+
+STDMETHODIMP CaptionStream::GetVolumeLevel(ULONG *level)
+{
+ debugfunc("level");
+ if (!level)
+ return E_POINTER;
+
+ *level = vol;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::SetVolumeLevel(ULONG level)
+{
+ debugfunc("%lu", level);
+ vol = level;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::GetBufferNotifySize(ULONG *size)
+{
+ debugfunc("size");
+ if (!size)
+ return E_POINTER;
+ *size = notify_size;
+ return S_OK;
+}
+
+STDMETHODIMP CaptionStream::SetBufferNotifySize(ULONG size)
+{
+ debugfunc("%lu", size);
+ notify_size = size;
+ return S_OK;
+}
diff --git a/UI/frontend-plugins/frontend-tools/captions-stream.hpp b/UI/frontend-plugins/frontend-tools/captions-stream.hpp
new file mode 100644
index 0000000..5461b7d
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/captions-stream.hpp
@@ -0,0 +1,119 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+class CircleBuf {
+ circlebuf buf = {};
+public:
+ inline ~CircleBuf() {circlebuf_free(&buf);}
+ inline operator circlebuf*() {return &buf;}
+ inline circlebuf *operator->() {return &buf;}
+};
+
+class Resampler {
+ audio_resampler_t *resampler = nullptr;
+
+public:
+ inline void Reset(const WAVEFORMATEX *wfex)
+ {
+ const struct audio_output_info *aoi =
+ audio_output_get_info(obs_get_audio());
+
+ struct resample_info src;
+ src.samples_per_sec = aoi->samples_per_sec;
+ src.format = aoi->format;
+ src.speakers = aoi->speakers;
+
+ struct resample_info dst;
+ dst.samples_per_sec = uint32_t(wfex->nSamplesPerSec);
+ dst.format = AUDIO_FORMAT_16BIT;
+ dst.speakers = (enum speaker_layout)wfex->nChannels;
+
+ if (resampler)
+ audio_resampler_destroy(resampler);
+ resampler = audio_resampler_create(&dst, &src);
+ }
+
+ inline ~Resampler() {audio_resampler_destroy(resampler);}
+ inline operator audio_resampler_t*() {return resampler;}
+};
+
+class CaptionStream : public ISpAudio {
+ volatile long refs = 1;
+ SPAUDIOBUFFERINFO buf_info = {};
+ ULONG notify_size = 0;
+ SPAUDIOSTATE state;
+ WinHandle event;
+ ULONG vol = 0;
+
+ std::condition_variable cv;
+ std::mutex m;
+ std::vector temp_buf;
+ WAVEFORMATEX format = {};
+ Resampler resampler;
+
+ CircleBuf buf;
+ ULONG wait_size = 0;
+ DWORD samplerate = 0;
+ ULARGE_INTEGER pos = {};
+ ULONGLONG write_pos = 0;
+
+public:
+ CaptionStream(DWORD samplerate);
+
+ void Stop();
+ void PushAudio(const struct audio_data *audio_data, bool muted);
+
+ // IUnknown methods
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppv) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ // ISequentialStream methods
+ STDMETHODIMP Read(void *data, ULONG bytes, ULONG *read_bytes) override;
+ STDMETHODIMP Write(const void *data, ULONG bytes, ULONG *written_bytes)
+ override;
+
+ // IStream methods
+ STDMETHODIMP Seek(LARGE_INTEGER move, DWORD origin,
+ ULARGE_INTEGER *new_pos) override;
+ STDMETHODIMP SetSize(ULARGE_INTEGER new_size) override;
+ STDMETHODIMP CopyTo(IStream *stream, ULARGE_INTEGER bytes,
+ ULARGE_INTEGER *read_bytes,
+ ULARGE_INTEGER *written_bytes) override;
+ STDMETHODIMP Commit(DWORD commit_flags) override;
+ STDMETHODIMP Revert(void) override;
+ STDMETHODIMP LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
+ DWORD type) override;
+ STDMETHODIMP UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size,
+ DWORD type) override;
+ STDMETHODIMP Stat(STATSTG *stg, DWORD flags) override;
+ STDMETHODIMP Clone(IStream **stream) override;
+
+ // ISpStreamFormat methods
+ STDMETHODIMP GetFormat(GUID *guid, WAVEFORMATEX **co_mem_wfex_out)
+ override;
+
+ // ISpAudio methods
+ STDMETHODIMP SetState(SPAUDIOSTATE state, ULONGLONG reserved) override;
+ STDMETHODIMP SetFormat(REFGUID guid_ref, const WAVEFORMATEX *wfex)
+ override;
+ STDMETHODIMP GetStatus(SPAUDIOSTATUS *status) override;
+ STDMETHODIMP SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info) override;
+ STDMETHODIMP GetBufferInfo(SPAUDIOBUFFERINFO *buf_info) override;
+ STDMETHODIMP GetDefaultFormat(GUID *format,
+ WAVEFORMATEX **co_mem_wfex_out) override;
+ STDMETHODIMP_(HANDLE) EventHandle(void) override;
+ STDMETHODIMP GetVolumeLevel(ULONG *level) override;
+ STDMETHODIMP SetVolumeLevel(ULONG level) override;
+ STDMETHODIMP GetBufferNotifySize(ULONG *size) override;
+ STDMETHODIMP SetBufferNotifySize(ULONG size) override;
+};
diff --git a/UI/frontend-plugins/frontend-tools/captions.cpp b/UI/frontend-plugins/frontend-tools/captions.cpp
new file mode 100644
index 0000000..c26d5b9
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/captions.cpp
@@ -0,0 +1,533 @@
+#include
+#include "captions-stream.hpp"
+#include "captions.hpp"
+#include "tool-helpers.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#define do_log(type, format, ...) blog(type, "[Captions] " format, \
+ ##__VA_ARGS__)
+
+#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__)
+#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
+
+using namespace std;
+
+struct obs_captions {
+ thread th;
+ recursive_mutex m;
+ WinHandle stop_event;
+
+ string source_name;
+ OBSWeakSource source;
+ LANGID lang_id;
+
+ void main_thread();
+ void start();
+ void stop();
+
+ inline obs_captions() :
+ stop_event(CreateEvent(nullptr, false, false, nullptr)),
+ lang_id(GetUserDefaultUILanguage())
+ {
+ }
+
+ inline ~obs_captions() {stop();}
+};
+
+static obs_captions *captions = nullptr;
+
+/* ------------------------------------------------------------------------- */
+
+struct locale_info {
+ DStr name;
+ LANGID id;
+
+ inline locale_info() {}
+ inline locale_info(const locale_info &) = delete;
+ inline locale_info(locale_info &&li)
+ : name(std::move(li.name)),
+ id(li.id)
+ {}
+};
+
+static void get_valid_locale_names(vector &names);
+static bool valid_lang(LANGID id);
+
+/* ------------------------------------------------------------------------- */
+
+CaptionsDialog::CaptionsDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui_CaptionsDialog)
+{
+ ui->setupUi(this);
+
+ lock_guard lock(captions->m);
+
+ auto cb = [this] (obs_source_t *source)
+ {
+ uint32_t caps = obs_source_get_output_flags(source);
+ QString name = obs_source_get_name(source);
+
+ if (caps & OBS_SOURCE_AUDIO)
+ ui->source->addItem(name);
+
+ OBSWeakSource weak = OBSGetWeakRef(source);
+ if (weak == captions->source)
+ ui->source->setCurrentText(name);
+ return true;
+ };
+
+ using cb_t = decltype(cb);
+
+ ui->source->blockSignals(true);
+ ui->source->addItem(QStringLiteral(""));
+ ui->source->setCurrentIndex(0);
+ obs_enum_sources([] (void *data, obs_source_t *source) {
+ return (*static_cast(data))(source);}, &cb);
+ ui->source->blockSignals(false);
+
+ ui->enable->blockSignals(true);
+ ui->enable->setChecked(captions->th.joinable());
+ ui->enable->blockSignals(false);
+
+ vector locales;
+ get_valid_locale_names(locales);
+
+ bool set_language = false;
+
+ ui->language->blockSignals(true);
+ for (int idx = 0; idx < (int)locales.size(); idx++) {
+ locale_info &locale = locales[idx];
+
+ ui->language->addItem(locale.name->array, (int)locale.id);
+
+ if (locale.id == captions->lang_id) {
+ ui->language->setCurrentIndex(idx);
+ set_language = true;
+ }
+ }
+
+ if (!set_language && locales.size())
+ ui->language->setCurrentIndex(0);
+
+ ui->language->blockSignals(false);
+
+ if (!locales.size()) {
+ ui->source->setEnabled(false);
+ ui->enable->setEnabled(false);
+ ui->language->setEnabled(false);
+
+ } else if (!set_language) {
+ bool started = captions->th.joinable();
+ if (started)
+ captions->stop();
+
+ captions->m.lock();
+ captions->lang_id = locales[0].id;
+ captions->m.unlock();
+
+ if (started)
+ captions->start();
+ }
+}
+
+void CaptionsDialog::on_source_currentIndexChanged(int)
+{
+ bool started = captions->th.joinable();
+ if (started)
+ captions->stop();
+
+ captions->m.lock();
+ captions->source_name = ui->source->currentText().toUtf8().constData();
+ captions->source = GetWeakSourceByName(captions->source_name.c_str());
+ captions->m.unlock();
+
+ if (started)
+ captions->start();
+}
+
+void CaptionsDialog::on_enable_clicked(bool checked)
+{
+ if (checked)
+ captions->start();
+ else
+ captions->stop();
+}
+
+void CaptionsDialog::on_language_currentIndexChanged(int)
+{
+ bool started = captions->th.joinable();
+ if (started)
+ captions->stop();
+
+ captions->m.lock();
+ captions->lang_id = (LANGID)ui->language->currentData().toInt();
+ captions->m.unlock();
+
+ if (started)
+ captions->start();
+}
+
+/* ------------------------------------------------------------------------- */
+
+void obs_captions::main_thread()
+try {
+ ComPtr audio;
+ ComPtr token;
+ ComPtr grammar;
+ ComPtr recognizer;
+ ComPtr context;
+ HRESULT hr;
+
+ auto cb = [&] (const struct audio_data *audio_data,
+ bool muted)
+ {
+ audio->PushAudio(audio_data, muted);
+ };
+
+ using cb_t = decltype(cb);
+
+ auto pre_cb = [] (void *param, obs_source_t*,
+ const struct audio_data *audio_data, bool muted)
+ {
+ return (*static_cast(param))(audio_data, muted);
+ };
+
+ os_set_thread_name(__FUNCTION__);
+
+ CoInitialize(nullptr);
+
+ wchar_t lang_str[32];
+ _snwprintf(lang_str, 31, L"language=%x", (int)captions->lang_id);
+
+ hr = SpFindBestToken(SPCAT_RECOGNIZERS, lang_str, nullptr, &token);
+ if (FAILED(hr))
+ throw HRError("SpFindBestToken failed", hr);
+
+ hr = CoCreateInstance(CLSID_SpInprocRecognizer, nullptr, CLSCTX_ALL,
+ __uuidof(ISpRecognizer), (void**)&recognizer);
+ if (FAILED(hr))
+ throw HRError("CoCreateInstance for recognizer failed", hr);
+
+ hr = recognizer->SetRecognizer(token);
+ if (FAILED(hr))
+ throw HRError("SetRecognizer failed", hr);
+
+ hr = recognizer->SetRecoState(SPRST_INACTIVE);
+ if (FAILED(hr))
+ throw HRError("SetRecoState(SPRST_INACTIVE) failed", hr);
+
+ hr = recognizer->CreateRecoContext(&context);
+ if (FAILED(hr))
+ throw HRError("CreateRecoContext failed", hr);
+
+ ULONGLONG interest = SPFEI(SPEI_RECOGNITION) |
+ SPFEI(SPEI_END_SR_STREAM);
+ hr = context->SetInterest(interest, interest);
+ if (FAILED(hr))
+ throw HRError("SetInterest failed", hr);
+
+ HANDLE notify;
+
+ hr = context->SetNotifyWin32Event();
+ if (FAILED(hr))
+ throw HRError("SetNotifyWin32Event", hr);
+
+ notify = context->GetNotifyEventHandle();
+ if (notify == INVALID_HANDLE_VALUE)
+ throw HRError("GetNotifyEventHandle failed", E_NOINTERFACE);
+
+ size_t sample_rate = audio_output_get_sample_rate(obs_get_audio());
+ audio = new CaptionStream((DWORD)sample_rate);
+ audio->Release();
+
+ hr = recognizer->SetInput(audio, false);
+ if (FAILED(hr))
+ throw HRError("SetInput failed", hr);
+
+ hr = context->CreateGrammar(1, &grammar);
+ if (FAILED(hr))
+ throw HRError("CreateGrammar failed", hr);
+
+ hr = grammar->LoadDictation(nullptr, SPLO_STATIC);
+ if (FAILED(hr))
+ throw HRError("LoadDictation failed", hr);
+
+ hr = grammar->SetDictationState(SPRS_ACTIVE);
+ if (FAILED(hr))
+ throw HRError("SetDictationState failed", hr);
+
+ hr = recognizer->SetRecoState(SPRST_ACTIVE);
+ if (FAILED(hr))
+ throw HRError("SetRecoState(SPRST_ACTIVE) failed", hr);
+
+ HANDLE events[] = {notify, stop_event};
+
+ {
+ captions->source = GetWeakSourceByName(
+ captions->source_name.c_str());
+ OBSSource strong = OBSGetStrongRef(source);
+ if (strong)
+ obs_source_add_audio_capture_callback(strong,
+ pre_cb, &cb);
+ }
+
+ for (;;) {
+ DWORD ret = WaitForMultipleObjects(2, events, false, INFINITE);
+ if (ret != WAIT_OBJECT_0)
+ break;
+
+ CSpEvent event;
+ bool exit = false;
+
+ while (event.GetFrom(context) == S_OK) {
+ if (event.eEventId == SPEI_RECOGNITION) {
+ ISpRecoResult *result = event.RecoResult();
+
+ CoTaskMemPtr text;
+ hr = result->GetText((ULONG)-1, (ULONG)-1,
+ true, &text, nullptr);
+ if (FAILED(hr))
+ continue;
+
+ char text_utf8[512];
+ os_wcs_to_utf8(text, 0, text_utf8, 512);
+
+ obs_output_t *output =
+ obs_frontend_get_streaming_output();
+ if (output)
+ obs_output_output_caption_text1(output,
+ text_utf8);
+
+ debug("\"%s\"", text_utf8);
+
+ obs_output_release(output);
+
+ } else if (event.eEventId == SPEI_END_SR_STREAM) {
+ exit = true;
+ break;
+ }
+ }
+
+ if (exit)
+ break;
+ }
+
+ {
+ OBSSource strong = OBSGetStrongRef(source);
+ if (strong)
+ obs_source_remove_audio_capture_callback(strong,
+ pre_cb, &cb);
+ }
+
+ audio->Stop();
+
+ CoUninitialize();
+
+} catch (HRError err) {
+ error("%s failed: %s (%lX)", __FUNCTION__, err.str, err.hr);
+ CoUninitialize();
+ captions->th.detach();
+}
+
+void obs_captions::start()
+{
+ if (!captions->th.joinable()) {
+ ResetEvent(captions->stop_event);
+
+ if (valid_lang(captions->lang_id))
+ captions->th = thread([] () {captions->main_thread();});
+ }
+}
+
+void obs_captions::stop()
+{
+ if (!captions->th.joinable())
+ return;
+
+ SetEvent(captions->stop_event);
+ captions->th.join();
+}
+
+static bool get_locale_name(LANGID id, char *out)
+{
+ wchar_t name[256];
+
+ int size = GetLocaleInfoW(id, LOCALE_SENGLISHLANGUAGENAME, name, 256);
+ if (size <= 0)
+ return false;
+
+ os_wcs_to_utf8(name, 0, out, 256);
+ return true;
+}
+
+static bool valid_lang(LANGID id)
+{
+ ComPtr token;
+ wchar_t lang_str[32];
+ HRESULT hr;
+
+ _snwprintf(lang_str, 31, L"language=%x", (int)id);
+
+ hr = SpFindBestToken(SPCAT_RECOGNIZERS, lang_str, nullptr, &token);
+ return SUCCEEDED(hr);
+}
+
+static void get_valid_locale_names(vector &locales)
+{
+ locale_info cur;
+ char locale_name[256];
+
+ static const LANGID default_locales[] = {
+ 0x0409,
+ 0x0401,
+ 0x0402,
+ 0x0403,
+ 0x0404,
+ 0x0405,
+ 0x0406,
+ 0x0407,
+ 0x0408,
+ 0x040a,
+ 0x040b,
+ 0x040c,
+ 0x040d,
+ 0x040e,
+ 0x040f,
+ 0x0410,
+ 0x0411,
+ 0x0412,
+ 0x0413,
+ 0x0414,
+ 0x0415,
+ 0x0416,
+ 0x0417,
+ 0x0418,
+ 0x0419,
+ 0x041a,
+ 0
+ };
+
+ /* ---------------------------------- */
+
+ LANGID def_id = GetUserDefaultUILanguage();
+ LANGID id = def_id;
+ if (valid_lang(id) && get_locale_name(id, locale_name)) {
+ dstr_copy(cur.name, obs_module_text(
+ "Captions.CurrentSystemLanguage"));
+ dstr_replace(cur.name, "%1", locale_name);
+ cur.id = id;
+
+ locales.push_back(std::move(cur));
+ }
+
+ /* ---------------------------------- */
+
+ const LANGID *locale = default_locales;
+
+ while (*locale) {
+ id = *locale;
+
+ if (id != def_id &&
+ valid_lang(id) &&
+ get_locale_name(id, locale_name)) {
+
+ dstr_copy(cur.name, locale_name);
+ cur.id = id;
+
+ locales.push_back(std::move(cur));
+ }
+
+ locale++;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+extern "C" void FreeCaptions()
+{
+ delete captions;
+ captions = nullptr;
+}
+
+static void obs_event(enum obs_frontend_event event, void *)
+{
+ if (event == OBS_FRONTEND_EVENT_EXIT)
+ FreeCaptions();
+}
+
+static void save_caption_data(obs_data_t *save_data, bool saving, void*)
+{
+ if (saving) {
+ lock_guard lock(captions->m);
+ obs_data_t *obj = obs_data_create();
+
+ obs_data_set_string(obj, "source",
+ captions->source_name.c_str());
+ obs_data_set_bool(obj, "enabled", captions->th.joinable());
+ obs_data_set_int(obj, "lang_id", captions->lang_id);
+
+ obs_data_set_obj(save_data, "captions", obj);
+ obs_data_release(obj);
+ } else {
+ captions->stop();
+
+ captions->m.lock();
+
+ obs_data_t *obj = obs_data_get_obj(save_data, "captions");
+ if (!obj)
+ obj = obs_data_create();
+
+ obs_data_set_default_int(obj, "lang_id",
+ GetUserDefaultUILanguage());
+
+ bool enabled = obs_data_get_bool(obj, "enabled");
+ captions->source_name = obs_data_get_string(obj, "source");
+ captions->lang_id = (int)obs_data_get_int(obj, "lang_id");
+ captions->source = GetWeakSourceByName(
+ captions->source_name.c_str());
+ obs_data_release(obj);
+
+ captions->m.unlock();
+
+ if (enabled)
+ captions->start();
+ }
+}
+
+extern "C" void InitCaptions()
+{
+ QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
+ obs_module_text("Captions"));
+
+ captions = new obs_captions;
+
+ auto cb = [] ()
+ {
+ obs_frontend_push_ui_translation(obs_module_get_string);
+
+ QWidget *window =
+ (QWidget*)obs_frontend_get_main_window();
+
+ CaptionsDialog dialog(window);
+ dialog.exec();
+
+ obs_frontend_pop_ui_translation();
+ };
+
+ obs_frontend_add_save_callback(save_caption_data, nullptr);
+ obs_frontend_add_event_callback(obs_event, nullptr);
+
+ action->connect(action, &QAction::triggered, cb);
+}
diff --git a/UI/frontend-plugins/frontend-tools/captions.hpp b/UI/frontend-plugins/frontend-tools/captions.hpp
new file mode 100644
index 0000000..d499755
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/captions.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include
+#include
+
+#include "ui_captions.h"
+
+class CaptionsDialog : public QDialog {
+ Q_OBJECT
+
+ std::unique_ptr ui;
+
+public:
+ CaptionsDialog(QWidget *parent);
+
+public slots:
+ void on_source_currentIndexChanged(int idx);
+ void on_enable_clicked(bool checked);
+ void on_language_currentIndexChanged(int idx);
+};
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini
index 2b17855..509d1c9 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="No canviar"
SceneSwitcher.OnNoMatch.SwitchTo="Canvia a:"
SceneSwitcher.CheckInterval="Comprova el títol de la finestra activa cada:"
SceneSwitcher.ActiveOrNotActive="El canviador de escena està:"
+InvalidRegex.Title="Expressió regular no vàlida"
+InvalidRegex.Text="La expressió regular que heu introduït no es vàlida."
Active="Actiu"
Inactive="Inactiu"
Start="Inicia"
Stop="Atura"
+Captions="Subtítols (Experimental)"
+Captions.AudioSource="Font d'àudio"
+Captions.CurrentSystemLanguage="Idioma actual del sistema (%1)"
+
+OutputTimer="Temporitzador de sortida"
+OutputTimer.Stream="Atura la transmissió després de:"
+OutputTimer.Record="Atura la gravació després de:"
+OutputTimer.Stream.StoppingIn="La transmissió s'aturarà en:"
+OutputTimer.Record.StoppingIn="La gravació s'aturarà en:"
+OutputTimer.Stream.EnableEverytime="Activa el temporitzador en cada transmissió"
+OutputTimer.Record.EnableEverytime="Activa el temporitzador en cada enregistrament"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini b/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini
index c8a4565..832040c 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Nepřepínat"
SceneSwitcher.OnNoMatch.SwitchTo="Přepnout na:"
SceneSwitcher.CheckInterval="Kontrolovat titulek aktivního okna každých:"
SceneSwitcher.ActiveOrNotActive="Přepínač scén je:"
+InvalidRegex.Title="Chybný regulární výraz"
+InvalidRegex.Text="Zadaný regulární výraz je chybný."
Active="Aktivní"
Inactive="Neaktivní"
Start="Spustit"
Stop="Zastavit"
+Captions="Titulky (experiment.)"
+Captions.AudioSource="Zdroj zvuku"
+Captions.CurrentSystemLanguage="Aktuální systémový jazyk (%1)"
+
+OutputTimer="Časovač"
+OutputTimer.Stream="Přestat vysílat po:"
+OutputTimer.Record="Přestat nahrávat po:"
+OutputTimer.Stream.StoppingIn="Vysílání se zastaví za:"
+OutputTimer.Record.StoppingIn="Nahrávání se zastaví za:"
+OutputTimer.Stream.EnableEverytime="Pokaždé povolit časovač vysílání"
+OutputTimer.Record.EnableEverytime="Pokaždé povolit časovač nahrávání"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini b/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini
index f72389c..f830d7c 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini
@@ -1,11 +1,25 @@
-SceneSwitcher="Automatisk sceneskifter"
-SceneSwitcher.OnNoMatch="Når intet vindue svarer til:"
+SceneSwitcher="Automatisk sceneomskifter"
+SceneSwitcher.OnNoMatch="Når intet vindue matcher:"
SceneSwitcher.OnNoMatch.DontSwitch="Skift ikke"
SceneSwitcher.OnNoMatch.SwitchTo="Skift til:"
SceneSwitcher.CheckInterval="Kontroller aktivt vinduestitel hvert:"
-SceneSwitcher.ActiveOrNotActive="Sceneskifter er:"
+SceneSwitcher.ActiveOrNotActive="Sceneomskifter er:"
+InvalidRegex.Title="Ugyldigt regulært udtryk"
+InvalidRegex.Text="Det af dig angivne regulære udtryk er ugyldigt."
Active="Aktiv"
Inactive="Inaktiv"
Start="Start"
Stop="Stop"
+Captions="Undertekster (eksperimentel)"
+Captions.AudioSource="Lydkilde"
+Captions.CurrentSystemLanguage="Aktuelt systemsprog (%1)"
+
+OutputTimer="Output-timer"
+OutputTimer.Stream="Stands streaming efter:"
+OutputTimer.Record="Stands optagelse efter:"
+OutputTimer.Stream.StoppingIn="Streaming standser om:"
+OutputTimer.Record.StoppingIn="Streaming standser om:"
+OutputTimer.Stream.EnableEverytime="Aktivér streaming-timer hver gang"
+OutputTimer.Record.EnableEverytime="Aktivér optage-timer hver gang"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini b/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini
index 4caf47e..97d1909 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Nicht wechseln"
SceneSwitcher.OnNoMatch.SwitchTo="Wechseln zu:"
SceneSwitcher.CheckInterval="Titel des aktiven Fensters überprüfen alle:"
SceneSwitcher.ActiveOrNotActive="Szenenwechsler ist:"
+InvalidRegex.Title="Ungültiger regulärer Ausdruck"
+InvalidRegex.Text="Der reguläre Ausdruck, den Sie eingegeben haben, ist ungültig."
Active="Aktiv"
Inactive="Inaktiv"
Start="Start"
Stop="Stop"
+Captions="Untertitel (experimentell)"
+Captions.AudioSource="Audioquelle"
+Captions.CurrentSystemLanguage="Aktuelle Systemsprache (%1)"
+
+OutputTimer="Ausgabetimer"
+OutputTimer.Stream="Stoppe Stream nach:"
+OutputTimer.Record="Stoppe Aufnahme nach:"
+OutputTimer.Stream.StoppingIn="Stream stoppt in:"
+OutputTimer.Record.StoppingIn="Aufnahme stoppt in:"
+OutputTimer.Stream.EnableEverytime="Streaming-Timer jedes Mal aktivieren"
+OutputTimer.Record.EnableEverytime="Aufnahme-Timer jedes Mal aktivieren"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini b/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini
index 63a4673..daf4b31 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini
@@ -4,7 +4,21 @@ SceneSwitcher.OnNoMatch.DontSwitch="Don't switch"
SceneSwitcher.OnNoMatch.SwitchTo="Switch to:"
SceneSwitcher.CheckInterval="Check active window title every:"
SceneSwitcher.ActiveOrNotActive="Scene Switcher is:"
+InvalidRegex.Title="Invalid Regular Expression"
+InvalidRegex.Text="The regular expression that you entered is invalid."
Active="Active"
Inactive="Inactive"
Start="Start"
Stop="Stop"
+
+Captions="Captions (Experimental)"
+Captions.AudioSource="Audio source"
+Captions.CurrentSystemLanguage="Current System Language (%1)"
+
+OutputTimer="Output Timer"
+OutputTimer.Stream="Stop streaming after:"
+OutputTimer.Record="Stop recording after:"
+OutputTimer.Stream.StoppingIn="Streaming stopping in:"
+OutputTimer.Record.StoppingIn="Recording stopping in:"
+OutputTimer.Stream.EnableEverytime="Enable streaming timer every time"
+OutputTimer.Record.EnableEverytime="Enable recording timer every time"
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini
index a08a8f9..4d76f15 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="No cambiar"
SceneSwitcher.OnNoMatch.SwitchTo="Cambiar a:"
SceneSwitcher.CheckInterval="Comprobar el título de la ventana activa cada:"
SceneSwitcher.ActiveOrNotActive="El cambiador de escena está:"
+InvalidRegex.Title="Expresión regular no válida"
+InvalidRegex.Text="La expresión regular que ha introducido no es válida."
Active="Activo"
Inactive="Inactivo"
Start="Iniciar"
Stop="Detener"
+Captions="Subtítulos (Experimental)"
+Captions.AudioSource="Fuente de audio"
+Captions.CurrentSystemLanguage="Idioma actual del sistema (%1)"
+
+OutputTimer="Temporizador de salida"
+OutputTimer.Stream="Detener la transmisión después de:"
+OutputTimer.Record="Detener la grabación después de:"
+OutputTimer.Stream.StoppingIn="Finalizando transmisión en:"
+OutputTimer.Record.StoppingIn="Finalizando grabación en:"
+OutputTimer.Stream.EnableEverytime="Activar temporizador en cada transmisión"
+OutputTimer.Record.EnableEverytime="Activar temporizador en cada grabación"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/et-EE.ini b/UI/frontend-plugins/frontend-tools/data/locale/et-EE.ini
new file mode 100644
index 0000000..be17c53
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/et-EE.ini
@@ -0,0 +1,21 @@
+SceneSwitcher="Automaatne stseeni vahetaja"
+SceneSwitcher.OnNoMatch="Kui üksi aken ei sobi:"
+SceneSwitcher.OnNoMatch.DontSwitch="Ära vaheta"
+SceneSwitcher.OnNoMatch.SwitchTo="Lülitu ümber:"
+SceneSwitcher.CheckInterval="Kontrollige aktiivse akna pealkiri iga:"
+SceneSwitcher.ActiveOrNotActive="Stseen vahetaja on:"
+Active="Aktiivne"
+Inactive="Inaktiivne"
+Start="Alusta"
+Stop="Lõpeta"
+
+Captions="Subtiitrid (eksperimentaalne)"
+Captions.AudioSource="Heli allikas"
+Captions.CurrentSystemLanguage="Praegune süsteemi keel (%1)"
+
+OutputTimer="Väljundi taimer"
+OutputTimer.Stream="Lõpeta voogedastus pärast:"
+OutputTimer.Record="Lõpeta voogedastus pärast:"
+OutputTimer.Stream.StoppingIn="Voogedastus lõppeb:"
+OutputTimer.Record.StoppingIn="Salvestamine lõppeb:"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini b/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini
index 99076b3..79f760e 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Ez aldatu"
SceneSwitcher.OnNoMatch.SwitchTo="Aldatu hona:"
SceneSwitcher.CheckInterval="Leiho aktiboaren titulua egiaztatzeko maiztasuna:"
SceneSwitcher.ActiveOrNotActive="Eszena aldatzailea dago:"
+InvalidRegex.Title="Adierazpen erregular baliogabea"
+InvalidRegex.Text="Sartu duzun adierazpen erregularra baliogabea da."
Active="Aktiboa"
Inactive="Inaktiboa"
Start="Hasi"
Stop="Gelditu"
+Captions="Epigrafeak (esperimentala)"
+Captions.AudioSource="Audio-iturburua"
+Captions.CurrentSystemLanguage="Sistemaren hizkuntza (%1)"
+
+OutputTimer="Irteera tenporizadorea"
+OutputTimer.Stream="Gelditu transmisioa hau pasata:"
+OutputTimer.Record="Gelditu grabazioa hau pasata:"
+OutputTimer.Stream.StoppingIn="Transmisioa geldituko da: hau barru:"
+OutputTimer.Record.StoppingIn="Grabazioa geldituko da hau barru:"
+OutputTimer.Stream.EnableEverytime="Gaitu transmisio tenporizadorea aldiro"
+OutputTimer.Record.EnableEverytime="Gaitu grabazio tenporizadorea aldiro"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini b/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini
index 0f20868..77a4bc6 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Älä vaihda"
SceneSwitcher.OnNoMatch.SwitchTo="Vaihda:"
SceneSwitcher.CheckInterval="Tarkista aktiivisen ikkunan otsikko:"
SceneSwitcher.ActiveOrNotActive="Skenen vaihtaja:"
+InvalidRegex.Title="Invalid Regular Expression"
+InvalidRegex.Text="The regular expression that you entered is invalid."
Active="Aktiivinen"
Inactive="Ei käytössä"
Start="Käynnistä"
Stop="Pysäytä"
+Captions="Kuvatekstit (Experimental)"
+Captions.AudioSource="Äänilähde"
+Captions.CurrentSystemLanguage="Järjestelmän kieli (%1)"
+
+OutputTimer="Ulostulo-ajastin"
+OutputTimer.Stream="Pysäyttää lähetyksen:"
+OutputTimer.Record="Pysäyttää tallennuksen:"
+OutputTimer.Stream.StoppingIn="Lähetys pysäytetään:"
+OutputTimer.Record.StoppingIn="Tallennus pysäytetään:"
+OutputTimer.Stream.EnableEverytime="Ota lähetysajastin käyttöön aina"
+OutputTimer.Record.EnableEverytime="Ota tallennusajastin käyttöön aina"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini b/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini
index 65d0b4c..1ffb41b 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Ne rien faire"
SceneSwitcher.OnNoMatch.SwitchTo="Basculer vers :"
SceneSwitcher.CheckInterval="Détecter le titre de la fenêtre active toutes les :"
SceneSwitcher.ActiveOrNotActive="Etat du sélecteur automatique :"
+InvalidRegex.Title="Expression invalide"
+InvalidRegex.Text="L'expression régulière saisie est invalide."
Active="Actif"
Inactive="Inactif"
Start="Démarrer"
Stop="Arrêter"
+Captions="Sous-titres (expérimental)"
+Captions.AudioSource="Source audio"
+Captions.CurrentSystemLanguage="Langue du système (%1)"
+
+OutputTimer="Minuterie des sorties"
+OutputTimer.Stream="Arrêter le streaming dans :"
+OutputTimer.Record="Arrêter l'enregistrement dans :"
+OutputTimer.Stream.StoppingIn="Arrêt du streaming dans :"
+OutputTimer.Record.StoppingIn="Arrêt de l'enregistrement dans :"
+OutputTimer.Stream.EnableEverytime="Activer le minuteur automatiquement à chaque stream"
+OutputTimer.Record.EnableEverytime="Activer le minuteur automatiquement à chaque enregistrement"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini b/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini
index fb81a54..ed94f35 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini
@@ -4,8 +4,19 @@ SceneSwitcher.OnNoMatch.DontSwitch="Ne menjaj"
SceneSwitcher.OnNoMatch.SwitchTo="Promeni na:"
SceneSwitcher.CheckInterval="Proveravaj naziv aktivnog prozora svakih:"
SceneSwitcher.ActiveOrNotActive="Menjač scena je:"
+InvalidRegex.Title="Neispravan regularni izraz"
+InvalidRegex.Text="Regularni izraz koji ste uneli nije ispravan."
Active="Aktivan"
Inactive="Neaktivan"
Start="Pokreni"
Stop="Zaustavi"
+
+OutputTimer="Tempomat snimanja i emitovanja"
+OutputTimer.Stream="Zaustavi emitovanje nakon:"
+OutputTimer.Record="Zaustavi snimanje nakon:"
+OutputTimer.Stream.StoppingIn="Prekidanje emitovanja za:"
+OutputTimer.Record.StoppingIn="Prekidanje snimanja za:"
+OutputTimer.Stream.EnableEverytime="Omogući štopovanje emitovanja svaki put"
+OutputTimer.Record.EnableEverytime="Omogući štopovanje snimanja svaki put"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini b/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini
index bfd99aa..94d6614 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Ne váltson"
SceneSwitcher.OnNoMatch.SwitchTo="Váltson:"
SceneSwitcher.CheckInterval="Aktív ablak ellenőrzése ennyi időközönként:"
SceneSwitcher.ActiveOrNotActive="Jelenet váltó:"
+InvalidRegex.Title="Érvénytelen kifejezés"
+InvalidRegex.Text="A megadott kifejezés érvénytelen."
Active="Aktív"
Inactive="Inaktiv"
Start="Start"
Stop="Stop"
+Captions="Feliratok (Kísérleti)"
+Captions.AudioSource="Audio forrás"
+Captions.CurrentSystemLanguage="Rendszer aktuális nyelve (%1)"
+
+OutputTimer="Kimeneti időzítő"
+OutputTimer.Stream="Stream leállítása:"
+OutputTimer.Record="Felvétel leállítása:"
+OutputTimer.Stream.StoppingIn="A stream leáll:"
+OutputTimer.Record.StoppingIn="Felvétel leáll:"
+OutputTimer.Stream.EnableEverytime="Stream időzítő indítása minden alkalommal"
+OutputTimer.Record.EnableEverytime="Felvétel időzítő indítása minden alkalommal"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/it-IT.ini b/UI/frontend-plugins/frontend-tools/data/locale/it-IT.ini
new file mode 100644
index 0000000..b8c6a87
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/it-IT.ini
@@ -0,0 +1,25 @@
+SceneSwitcher="Cambia scena automatico"
+SceneSwitcher.OnNoMatch="Quando nessuna scena coincide a:"
+SceneSwitcher.OnNoMatch.DontSwitch="Non passare"
+SceneSwitcher.OnNoMatch.SwitchTo="Passa a:"
+SceneSwitcher.CheckInterval="Controlla il titolo della finestra attiva ogni:"
+SceneSwitcher.ActiveOrNotActive="Lo scene switcher è:"
+InvalidRegex.Title="Espressione regolare non valida"
+InvalidRegex.Text="L'espressione regolare che hai inserito non è valido."
+Active="Attivo"
+Inactive="Inattivo"
+Start="Inizio"
+Stop="Stop"
+
+Captions="Sottotitoli (Sperimentale)"
+Captions.AudioSource="Fonte audio"
+Captions.CurrentSystemLanguage="Lingua del sistema in uso (%1)"
+
+OutputTimer="Timer Output"
+OutputTimer.Stream="Termina diretta dopo:"
+OutputTimer.Record="Termina registrazione dopo:"
+OutputTimer.Stream.StoppingIn="La diretta terminerà in:"
+OutputTimer.Record.StoppingIn="La registrazione terminerà in:"
+OutputTimer.Stream.EnableEverytime="Abilita il timer per lo streaming ogni volta"
+OutputTimer.Record.EnableEverytime="Abilita il timer per la registrazione ogni volta"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini b/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini
index 714c79c..6005f8a 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="切り替えない"
SceneSwitcher.OnNoMatch.SwitchTo="切り替える:"
SceneSwitcher.CheckInterval="アクティブウィンドウタイトルを確認する間隔:"
SceneSwitcher.ActiveOrNotActive="シーンスイッチャーは:"
+InvalidRegex.Title="無効な正規表現"
+InvalidRegex.Text="入力した正規表現は有効ではありません。"
Active="アクティブ"
Inactive="非アクティブ"
Start="開始"
Stop="停止"
+Captions="見出し (実験的)"
+Captions.AudioSource="音声ソース"
+Captions.CurrentSystemLanguage="現在のシステム言語 (%1)"
+
+OutputTimer="出力タイマー"
+OutputTimer.Stream="配信停止の時間設定:"
+OutputTimer.Record="録画停止の時間設定:"
+OutputTimer.Stream.StoppingIn="配信停止まで:"
+OutputTimer.Record.StoppingIn="録画停止まで:"
+OutputTimer.Stream.EnableEverytime="毎回配信タイマーを有効にする"
+OutputTimer.Record.EnableEverytime="毎回録画タイマーを有効にする"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini b/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini
index cbfee50..0bb7dc2 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="전환하지 않음"
SceneSwitcher.OnNoMatch.SwitchTo="여기로 전환:"
SceneSwitcher.CheckInterval="활성화된 윈도우 제목을 확인:"
SceneSwitcher.ActiveOrNotActive="장면 전환기:"
+InvalidRegex.Title="유효하지 않은 정규 표현"
+InvalidRegex.Text="입력한 정규 표현이 유효하지 않습니다."
Active="활성화"
Inactive="비활성화"
Start="시작"
Stop="중단"
+Captions="자막 (실험적 기능)"
+Captions.AudioSource="오디오 소스"
+Captions.CurrentSystemLanguage="현재 시스템 언어 (%1)"
+
+OutputTimer="출력 시간 설정"
+OutputTimer.Stream="이 시간 이후 방송 중단:"
+OutputTimer.Record="이 시간 이후 녹화 중단:"
+OutputTimer.Stream.StoppingIn="방송 중지까지 남은 시간:"
+OutputTimer.Record.StoppingIn="녹화 중지까지 남은 시간:"
+OutputTimer.Stream.EnableEverytime="매번 방송 시간 기록기 활성화"
+OutputTimer.Record.EnableEverytime="매번 녹화 시간 기록기 활성화"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ms-MY.ini b/UI/frontend-plugins/frontend-tools/data/locale/ms-MY.ini
new file mode 100644
index 0000000..36ec39f
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/ms-MY.ini
@@ -0,0 +1,11 @@
+Active="Aktif"
+Inactive="Tidak Aktif"
+Start="Mula"
+Stop="Berhenti"
+
+
+OutputTimer.Stream="Berhenti 'streaming' selepas:"
+OutputTimer.Record="Berhenti merakam selepas:"
+OutputTimer.Stream.StoppingIn="'Streaming' dihentikan dalam:"
+OutputTimer.Record.StoppingIn="Rakaman dihentikan dalam:"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini b/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini
new file mode 100644
index 0000000..e525d27
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini
@@ -0,0 +1,25 @@
+SceneSwitcher="Automatisk Scene Skifter"
+SceneSwitcher.OnNoMatch="Når ingen vindu passer overens:"
+SceneSwitcher.OnNoMatch.DontSwitch="Ikke bytt"
+SceneSwitcher.OnNoMatch.SwitchTo="Bytt til:"
+SceneSwitcher.CheckInterval="Sjekk aktivt vindu hver:"
+SceneSwitcher.ActiveOrNotActive="Sceneskifter er:"
+InvalidRegex.Title="Ugyldig regulært utrykk"
+InvalidRegex.Text="Det regulære utrykket du har angitt er ugyldig."
+Active="Aktiv"
+Inactive="Inaktiv"
+Start="Start"
+Stop="Stopp"
+
+Captions="Bildetekster (eksperimentell)"
+Captions.AudioSource="Lyd kilde"
+Captions.CurrentSystemLanguage="Någjeldende System Språk"
+
+OutputTimer="Stoppeklokke"
+OutputTimer.Stream="Stopp streaming etter:"
+OutputTimer.Record="Stopp opptak etter:"
+OutputTimer.Stream.StoppingIn="Streaming stopper om:"
+OutputTimer.Record.StoppingIn="Opptak stopper om:"
+OutputTimer.Stream.EnableEverytime="Aktiver streaming timer hver gang"
+OutputTimer.Record.EnableEverytime="Aktiver opptaks timer hver gang"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini b/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini
index b785c86..661d16c 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Wissel niet"
SceneSwitcher.OnNoMatch.SwitchTo="Wissel naar:"
SceneSwitcher.CheckInterval="Controleer actieve venstertitel elke:"
SceneSwitcher.ActiveOrNotActive="Scènewisselaar is:"
+InvalidRegex.Title="Ongeldige Reguliere Expressie"
+InvalidRegex.Text="De ingevoerde reguliere expressie is ongeldig."
Active="Actief"
Inactive="Inactief"
Start="Start"
Stop="Stop"
+Captions="Ondertiteling (Experimenteel)"
+Captions.AudioSource="Audiobron"
+Captions.CurrentSystemLanguage="Huidige Systeemtaal (%1)"
+
+OutputTimer="Uitvoertimer"
+OutputTimer.Stream="Stop met streamen na:"
+OutputTimer.Record="Stop met opnemen na:"
+OutputTimer.Stream.StoppingIn="Stream stopt over:"
+OutputTimer.Record.StoppingIn="Opname stopt over:"
+OutputTimer.Stream.EnableEverytime="Schakel streaming timer elke keer in"
+OutputTimer.Record.EnableEverytime="Schakel opnametimer elke keer in"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini b/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini
index dd2d18d..79b8a6a 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Nie przełączaj"
SceneSwitcher.OnNoMatch.SwitchTo="Przełącz na:"
SceneSwitcher.CheckInterval="Sprawdź tytuł aktywnego okna co:"
SceneSwitcher.ActiveOrNotActive="Przełączanie scen jest:"
+InvalidRegex.Title="Nieprawidłowe wyrażenie regularne"
+InvalidRegex.Text="Podane wyrażenie regularne jest nieprawidłowe."
Active="Aktywne"
Inactive="Nieaktywne"
Start="Start"
Stop="Stop"
+Captions="Podpisy (eksperymentalne)"
+Captions.AudioSource="Źródła dźwięku"
+Captions.CurrentSystemLanguage="Obecny język systemu (%1)"
+
+OutputTimer="Wyłącznik czasowy"
+OutputTimer.Stream="Zatrzymaj stream po:"
+OutputTimer.Record="Zatrzymaj nagrywanie po:"
+OutputTimer.Stream.StoppingIn="Zatrzymanie streamu za:"
+OutputTimer.Record.StoppingIn="Zatrzymanie nagrywania za:"
+OutputTimer.Stream.EnableEverytime="Włącz timer streamu za każdym razem"
+OutputTimer.Record.EnableEverytime="Włącz timer nagrywania za każdym razem"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini b/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini
index 5a6a4eb..e3770c5 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Não alternar"
SceneSwitcher.OnNoMatch.SwitchTo="Alternar para:"
SceneSwitcher.CheckInterval="Checar o título da janela ativa a cada:"
SceneSwitcher.ActiveOrNotActive="O alternador de cenas está:"
+InvalidRegex.Title="Expressão Regular inválida"
+InvalidRegex.Text="A expressão regular que você inseriu é inválida."
Active="Ligado"
Inactive="Desligado"
Start="Iniciar"
Stop="Parar"
+Captions="Legendas (Experimental)"
+Captions.AudioSource="Fonte de Áudio"
+Captions.CurrentSystemLanguage="Idioma Atual do Sistema (%1)"
+
+OutputTimer="Temporizador de saída"
+OutputTimer.Stream="Parar a transmissão após:"
+OutputTimer.Record="Parar a gravação após:"
+OutputTimer.Stream.StoppingIn="A transmissão irá parar em:"
+OutputTimer.Record.StoppingIn="A gravação irá parar em:"
+OutputTimer.Stream.EnableEverytime="Ativar o timer streaming o tempo todo"
+OutputTimer.Record.EnableEverytime="Ativar o timer de gravação o tempo todo"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini b/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini
new file mode 100644
index 0000000..b9363bf
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini
@@ -0,0 +1,20 @@
+SceneSwitcher="Troca automática de cenas"
+SceneSwitcher.OnNoMatch="Quando nenhuma janela corresponder:"
+SceneSwitcher.OnNoMatch.DontSwitch="Não trocar"
+SceneSwitcher.OnNoMatch.SwitchTo="Trocar para:"
+SceneSwitcher.CheckInterval="Verificar o nome da janela ativa a cada:"
+SceneSwitcher.ActiveOrNotActive="A troca de cenas está:"
+InvalidRegex.Title="Expressão regular inválida"
+InvalidRegex.Text="A expressão regular que introduziu é inválida."
+Active="Ativa"
+Inactive="Inativa"
+Start="Iniciar"
+Stop="Parar"
+
+
+OutputTimer="Temporizador de saída"
+OutputTimer.Stream="Para a transmissão após:"
+OutputTimer.Record="Parar a gravação após:"
+OutputTimer.Stream.StoppingIn="A transmissão irá parar em:"
+OutputTimer.Record.StoppingIn="A gravação irá parar em:"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ro-RO.ini b/UI/frontend-plugins/frontend-tools/data/locale/ro-RO.ini
new file mode 100644
index 0000000..2f223b9
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/ro-RO.ini
@@ -0,0 +1,13 @@
+SceneSwitcher="Schimbator automat de scenă"
+SceneSwitcher.OnNoMatch="Cand nici o fereastra nu se potriveste:"
+SceneSwitcher.OnNoMatch.SwitchTo="Schimbă la:"
+Active="Activ"
+Inactive="Inactiv"
+Start="Pornire"
+Stop="Oprire"
+
+Captions.AudioSource="Sursa audio"
+Captions.CurrentSystemLanguage="Limba curentă a sistemului (%1)"
+
+OutputTimer.Record="Opriți inregistrarea dupa:"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini b/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini
index 831e0d0..84e8e53 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Не переключать"
SceneSwitcher.OnNoMatch.SwitchTo="Переключать на:"
SceneSwitcher.CheckInterval="Проверять имя активного окна каждые:"
SceneSwitcher.ActiveOrNotActive="Переключатель сцен:"
+InvalidRegex.Title="Недопустимое регулярное выражение"
+InvalidRegex.Text="Регулярное выражение, которое вы ввели, содержит ошибки."
Active="Активен"
Inactive="Неактивен"
Start="Запустить"
Stop="Остановить"
+Captions="Субтитры (экспериментально)"
+Captions.AudioSource="Источник звука"
+Captions.CurrentSystemLanguage="Текущий язык системы (%1)"
+
+OutputTimer="Таймер записи и стрима"
+OutputTimer.Stream="Завершить стрим через:"
+OutputTimer.Record="Завершить запись через:"
+OutputTimer.Stream.StoppingIn="Стрим будет завершён через:"
+OutputTimer.Record.StoppingIn="Запись будет завершена через:"
+OutputTimer.Stream.EnableEverytime="Включать таймер стрима каждый раз"
+OutputTimer.Record.EnableEverytime="Включать таймер записи каждый раз"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sk-SK.ini b/UI/frontend-plugins/frontend-tools/data/locale/sk-SK.ini
new file mode 100644
index 0000000..b5d2316
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/sk-SK.ini
@@ -0,0 +1,10 @@
+SceneSwitcher.CheckInterval="Kontrolovať aktívne okno každých:"
+Active="Aktívny"
+Inactive="Neaktivní"
+Start="Spustiť"
+Stop="Zastaviť"
+
+
+OutputTimer.Stream="Zastaviť stream po:"
+OutputTimer.Record="Zastaviť nahrávanie po:"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini b/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini
index fb81a54..ed94f35 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini
@@ -4,8 +4,19 @@ SceneSwitcher.OnNoMatch.DontSwitch="Ne menjaj"
SceneSwitcher.OnNoMatch.SwitchTo="Promeni na:"
SceneSwitcher.CheckInterval="Proveravaj naziv aktivnog prozora svakih:"
SceneSwitcher.ActiveOrNotActive="Menjač scena je:"
+InvalidRegex.Title="Neispravan regularni izraz"
+InvalidRegex.Text="Regularni izraz koji ste uneli nije ispravan."
Active="Aktivan"
Inactive="Neaktivan"
Start="Pokreni"
Stop="Zaustavi"
+
+OutputTimer="Tempomat snimanja i emitovanja"
+OutputTimer.Stream="Zaustavi emitovanje nakon:"
+OutputTimer.Record="Zaustavi snimanje nakon:"
+OutputTimer.Stream.StoppingIn="Prekidanje emitovanja za:"
+OutputTimer.Record.StoppingIn="Prekidanje snimanja za:"
+OutputTimer.Stream.EnableEverytime="Omogući štopovanje emitovanja svaki put"
+OutputTimer.Record.EnableEverytime="Omogući štopovanje snimanja svaki put"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini b/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini
index 983378f..f40fa5a 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini
@@ -4,8 +4,19 @@ SceneSwitcher.OnNoMatch.DontSwitch="Не мењај"
SceneSwitcher.OnNoMatch.SwitchTo="Промени на:"
SceneSwitcher.CheckInterval="Проверавај назив активног прозора сваких:"
SceneSwitcher.ActiveOrNotActive="Мењач сцена је:"
+InvalidRegex.Title="Неисправан регуларни израз"
+InvalidRegex.Text="Регуларни израз који сте унели није исправан."
Active="Активан"
Inactive="Неактиван"
Start="Покрени"
Stop="Заустави"
+
+OutputTimer="Темпомат снимања и емитовања"
+OutputTimer.Stream="Заустави емитовање након:"
+OutputTimer.Record="Заустави снимање након:"
+OutputTimer.Stream.StoppingIn="Прекидање емитовања за:"
+OutputTimer.Record.StoppingIn="Прекидање снимања за:"
+OutputTimer.Stream.EnableEverytime="Омогући штоповање емитовање сваки пут"
+OutputTimer.Record.EnableEverytime="Омогући штоповање снимања сваки пут"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini b/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini
index a2f6330..4740873 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Byt inte"
SceneSwitcher.OnNoMatch.SwitchTo="Byt till:"
SceneSwitcher.CheckInterval="Kontrollera aktiv fönstertitel varje:"
SceneSwitcher.ActiveOrNotActive="Scenbytaren är:"
+InvalidRegex.Title="Ogiltigt reguljärt uttryck"
+InvalidRegex.Text="Det reguljära uttrycket du angav är ogiltigt."
Active="Aktiv"
Inactive="Inaktiv"
Start="Starta"
Stop="Stoppa"
+Captions="Undertexter (experimentell)"
+Captions.AudioSource="Ljudkälla"
+Captions.CurrentSystemLanguage="Aktuellt systemspråk (%1)"
+
+OutputTimer="Utdatatimer"
+OutputTimer.Stream="Sluta streama efter:"
+OutputTimer.Record="Stoppa inspelningen efter:"
+OutputTimer.Stream.StoppingIn="Streamen stoppas om:"
+OutputTimer.Record.StoppingIn="Inspelningen stoppas om:"
+OutputTimer.Stream.EnableEverytime="Aktivera strömtimer varje gång"
+OutputTimer.Record.EnableEverytime="Aktivera inspelningstimer varje gång"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/tr-TR.ini b/UI/frontend-plugins/frontend-tools/data/locale/tr-TR.ini
new file mode 100644
index 0000000..287208b
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/tr-TR.ini
@@ -0,0 +1,25 @@
+SceneSwitcher="Otomatik Sahne Değiştirici"
+SceneSwitcher.OnNoMatch="Hiçbir pencere ile eşleşmez ise:"
+SceneSwitcher.OnNoMatch.DontSwitch="Geçiş yapma"
+SceneSwitcher.OnNoMatch.SwitchTo="Şuna geç:"
+SceneSwitcher.CheckInterval="Etkin pencere başlığını kontrol et:"
+SceneSwitcher.ActiveOrNotActive="Sahne Değiştirici:"
+InvalidRegex.Title="Geçersiz Kurallı İfade"
+InvalidRegex.Text="Girdiğiniz kurallı ifade geçersiz."
+Active="Etkin"
+Inactive="Devre Dışı"
+Start="Başlat"
+Stop="Durdur"
+
+Captions="Altyazı (Deneysel)"
+Captions.AudioSource="Ses kaynağı"
+Captions.CurrentSystemLanguage="Geçerli Sistem Dili (%1)"
+
+OutputTimer="Çıkış Zamanlayıcısı"
+OutputTimer.Stream="Şuradan sonra yayını durdur:"
+OutputTimer.Record="Şuradan sonra kaydı durdur:"
+OutputTimer.Stream.StoppingIn="Yayın durduruluyor:"
+OutputTimer.Record.StoppingIn="Kayıt durduruluyor:"
+OutputTimer.Stream.EnableEverytime="Her zaman yayın zamanlayıcıyı etkinleştir"
+OutputTimer.Record.EnableEverytime="Her zaman kayıt zamanlayıcıyı etkinleştir"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini b/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini
index 12a1a0b..ba03f1b 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="Нічого не робити"
SceneSwitcher.OnNoMatch.SwitchTo="Перейти до:"
SceneSwitcher.CheckInterval="Перевіряти заголовок активного вікна кожні:"
SceneSwitcher.ActiveOrNotActive="Автоматичний перехід між Сценами:"
+InvalidRegex.Title="Неприпустимий регулярний вираз"
+InvalidRegex.Text="Ви ввели неприпустимий регулярний вираз (шаблон)."
Active="Активний"
Inactive="Неактивний"
Start="Запустити"
Stop="Зупинити"
+Captions="Субтитри (експериментально)"
+Captions.AudioSource="Джерело Аудіо"
+Captions.CurrentSystemLanguage="Поточна мова Системи (%1)"
+
+OutputTimer="Таймер для Виводу"
+OutputTimer.Stream="Закінчити трансляцію за:"
+OutputTimer.Record="Зупинити запис за:"
+OutputTimer.Stream.StoppingIn="Трансляція припиниться за:"
+OutputTimer.Record.StoppingIn="Запис зупиниться за:"
+OutputTimer.Stream.EnableEverytime="Щоразу запускається трансляція - вмикати Таймер для Виводу"
+OutputTimer.Record.EnableEverytime="Щоразу починається запис - вмикати Таймер для Виводу"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini b/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini
new file mode 100644
index 0000000..bd8a79c
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini
@@ -0,0 +1,17 @@
+SceneSwitcher="Tự động chuyển cảnh"
+SceneSwitcher.OnNoMatch="Khi cửa sổ không khớp:"
+SceneSwitcher.OnNoMatch.DontSwitch="Không chuyển"
+SceneSwitcher.OnNoMatch.SwitchTo="Chuyển sang:"
+SceneSwitcher.CheckInterval="Kiểm tra tiêu đề cửa sổ mỗi:"
+SceneSwitcher.ActiveOrNotActive="Chuyển cảnh đang:"
+Active="Đang hoạt động"
+Inactive="Không hoạt động"
+Start="Bắt đầu"
+Stop="Dừng"
+
+
+OutputTimer.Stream="Dừng stream sau:"
+OutputTimer.Record="Dừng ghi video sau:"
+OutputTimer.Stream.StoppingIn="Stream sẽ dừng trong:"
+OutputTimer.Record.StoppingIn="Quay video sẽ dừng trong:"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini b/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini
index 1ae756f..eb09aa7 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="不切换"
SceneSwitcher.OnNoMatch.SwitchTo="切换到:"
SceneSwitcher.CheckInterval="检查活动窗口的标题,每:"
SceneSwitcher.ActiveOrNotActive="场景切换器是:"
+InvalidRegex.Title="无效的正则表达式"
+InvalidRegex.Text="您输入的正则表达式是无效的。"
Active="已激活"
Inactive="未激活"
Start="开始"
Stop="停止"
+Captions="标题(实验)"
+Captions.AudioSource="音频源"
+Captions.CurrentSystemLanguage="当前系统语言 (%1)"
+
+OutputTimer="输出计时器"
+OutputTimer.Stream="停止流处理后:"
+OutputTimer.Record="停止录制后:"
+OutputTimer.Stream.StoppingIn="串流停止在:"
+OutputTimer.Record.StoppingIn="录制停止在:"
+OutputTimer.Stream.EnableEverytime="每次启用流计时器"
+OutputTimer.Record.EnableEverytime="每次启用录制计时器"
+
diff --git a/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini b/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini
index ac7668a..17412b8 100644
--- a/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini
+++ b/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini
@@ -4,8 +4,22 @@ SceneSwitcher.OnNoMatch.DontSwitch="不切換"
SceneSwitcher.OnNoMatch.SwitchTo="切換到︰"
SceneSwitcher.CheckInterval="檢查使用中視窗標題的頻率︰"
SceneSwitcher.ActiveOrNotActive="場景切換器︰"
+InvalidRegex.Title="無效的正規表達式"
+InvalidRegex.Text="您輸入的正則運算式不正確"
Active="啟動中"
Inactive="未啟動"
Start="開始"
Stop="停止"
+Captions="標題 (實驗)"
+Captions.AudioSource="音訊源"
+Captions.CurrentSystemLanguage="目前系統語言 (%1)"
+
+OutputTimer="輸出計時器"
+OutputTimer.Stream="在下面時間後停止串流:"
+OutputTimer.Record="在下面時間後停止錄影:"
+OutputTimer.Stream.StoppingIn="串流將在下面時間內停止"
+OutputTimer.Record.StoppingIn="錄影將在下面時間內停止"
+OutputTimer.Stream.EnableEverytime="每次都啟動串流計時器"
+OutputTimer.Record.EnableEverytime="每次都啟動錄影計時器"
+
diff --git a/UI/frontend-plugins/frontend-tools/forms/captions.ui b/UI/frontend-plugins/frontend-tools/forms/captions.ui
new file mode 100644
index 0000000..4f08214
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/forms/captions.ui
@@ -0,0 +1,132 @@
+
+
+ CaptionsDialog
+
+
+
+ 0
+ 0
+ 519
+ 140
+
+
+
+ Captions
+
+
+ -
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+ -
+
+
+ Captions.AudioSource
+
+
+ source
+
+
+
+ -
+
+
+ QComboBox::InsertAlphabetically
+
+
+
+ -
+
+
+ Enable
+
+
+
+ -
+
+
+ Basic.Settings.General.Language
+
+
+ language
+
+
+
+ -
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ OK
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+
+ accept
+ clicked()
+ CaptionsDialog
+ accept()
+
+
+ 268
+ 331
+
+
+ 229
+ -11
+
+
+
+
+
diff --git a/UI/frontend-plugins/frontend-tools/forms/output-timer.ui b/UI/frontend-plugins/frontend-tools/forms/output-timer.ui
new file mode 100644
index 0000000..b9ea3d9
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/forms/output-timer.ui
@@ -0,0 +1,208 @@
+
+
+ OutputTimer
+
+
+
+ 0
+ 0
+ 600
+ 200
+
+
+
+ OutputTimer
+
+
+ -
+
+
+ OutputTimer.Stream
+
+
+
+ -
+
+
+ 0
+
+
+ 24
+
+
+ 0
+
+
+
+ -
+
+
+ Hours
+
+
+
+ -
+
+
+ 59
+
+
+ 0
+
+
+
+ -
+
+
+ Minutes
+
+
+
+ -
+
+
+ 0
+
+
+ 59
+
+
+ 30
+
+
+
+ -
+
+
+ Seconds
+
+
+
+ -
+
+
+ Start
+
+
+
+ -
+
+
+ OutputTimer.Stream.StoppingIn
+
+
+
+ -
+
+
+ 00:00:00
+
+
+
+ -
+
+
+ OutputTimer.Record
+
+
+
+ -
+
+
+ 0
+
+
+ 24
+
+
+ 0
+
+
+
+ -
+
+
+ Hours
+
+
+
+ -
+
+
+ 0
+
+
+ 59
+
+
+ 0
+
+
+
+ -
+
+
+ Minutes
+
+
+
+ -
+
+
+ 0
+
+
+ 59
+
+
+ 30
+
+
+
+ -
+
+
+ Seconds
+
+
+
+ -
+
+
+ Start
+
+
+
+ -
+
+
+ OutputTimer.Record.StoppingIn
+
+
+
+ -
+
+
+ 00:00:00
+
+
+
+ -
+
+
+ OutputTimer.Stream.EnableEverytime
+
+
+
+ -
+
+
+ OutputTimer.Record.EnableEverytime
+
+
+
+
+
+
+
+
diff --git a/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in b/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in
new file mode 100644
index 0000000..3389a42
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in
@@ -0,0 +1,3 @@
+#pragma once
+
+#define BUILD_CAPTIONS @BUILD_CAPTIONS@
diff --git a/UI/frontend-plugins/frontend-tools/frontend-tools.c b/UI/frontend-plugins/frontend-tools/frontend-tools.c
index 3826f04..a586b88 100644
--- a/UI/frontend-plugins/frontend-tools/frontend-tools.c
+++ b/UI/frontend-plugins/frontend-tools/frontend-tools.c
@@ -1,18 +1,41 @@
#include
+#include "frontend-tools-config.h"
OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US")
+#if defined(_WIN32) || defined(__APPLE__)
void InitSceneSwitcher();
void FreeSceneSwitcher();
+#endif
+
+#if defined(_WIN32) && BUILD_CAPTIONS
+void InitCaptions();
+void FreeCaptions();
+#endif
+
+void InitOutputTimer();
+void FreeOutputTimer();
bool obs_module_load(void)
{
+#if defined(_WIN32) || defined(__APPLE__)
InitSceneSwitcher();
+#endif
+#if defined(_WIN32) && BUILD_CAPTIONS
+ InitCaptions();
+#endif
+ InitOutputTimer();
return true;
}
void obs_module_unload(void)
{
+#if defined(_WIN32) || defined(__APPLE__)
FreeSceneSwitcher();
+#endif
+#if defined(_WIN32) && BUILD_CAPTIONS
+ FreeCaptions();
+#endif
+ FreeOutputTimer();
}
diff --git a/UI/frontend-plugins/frontend-tools/output-timer.cpp b/UI/frontend-plugins/frontend-tools/output-timer.cpp
new file mode 100644
index 0000000..441e929
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/output-timer.cpp
@@ -0,0 +1,312 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "output-timer.hpp"
+
+using namespace std;
+
+OutputTimer *ot;
+
+OutputTimer::OutputTimer(QWidget *parent)
+ : QDialog(parent),
+ ui(new Ui_OutputTimer)
+{
+ ui->setupUi(this);
+
+ QObject::connect(ui->outputTimerStream, SIGNAL(clicked()), this,
+ SLOT(StreamingTimerButton()));
+ QObject::connect(ui->outputTimerRecord, SIGNAL(clicked()), this,
+ SLOT(RecordingTimerButton()));
+
+ streamingTimer = new QTimer(this);
+ streamingTimerDisplay = new QTimer(this);
+
+ recordingTimer = new QTimer(this);
+ recordingTimerDisplay = new QTimer(this);
+}
+
+void OutputTimer::closeEvent(QCloseEvent*)
+{
+ obs_frontend_save();
+}
+
+void OutputTimer::StreamingTimerButton()
+{
+ if (!obs_frontend_streaming_active()) {
+ obs_frontend_streaming_start();
+ } else if (streamingAlreadyActive) {
+ StreamTimerStart();
+ streamingAlreadyActive = false;
+ } else if (obs_frontend_streaming_active()) {
+ obs_frontend_streaming_stop();
+ }
+}
+
+void OutputTimer::RecordingTimerButton()
+{
+ if (!obs_frontend_recording_active()) {
+ obs_frontend_recording_start();
+ } else if (recordingAlreadyActive) {
+ RecordTimerStart();
+ recordingAlreadyActive = false;
+ } else if (obs_frontend_recording_active()) {
+ obs_frontend_recording_stop();
+ }
+}
+
+void OutputTimer::StreamTimerStart()
+{
+ if (!isVisible() && ui->autoStartStreamTimer->isChecked() == false) {
+ streamingAlreadyActive = true;
+ return;
+ }
+
+ int hours = ui->streamingTimerHours->value();
+ int minutes = ui->streamingTimerMinutes->value();
+ int seconds = ui->streamingTimerSeconds->value();
+
+ int total = (((hours * 3600) +
+ (minutes * 60)) +
+ seconds) * 1000;
+
+ if (total == 0)
+ total = 1000;
+
+ streamingTimer->setInterval(total);
+ streamingTimer->setSingleShot(true);
+
+ QObject::connect(streamingTimer, SIGNAL(timeout()),
+ SLOT(EventStopStreaming()));
+
+ QObject::connect(streamingTimerDisplay, SIGNAL(timeout()), this,
+ SLOT(UpdateStreamTimerDisplay()));
+
+ streamingTimer->start();
+ streamingTimerDisplay->start(1000);
+ ui->outputTimerStream->setText(obs_module_text("Stop"));
+
+ UpdateStreamTimerDisplay();
+}
+
+void OutputTimer::RecordTimerStart()
+{
+ if (!isVisible() && ui->autoStartRecordTimer->isChecked() == false) {
+ recordingAlreadyActive = true;
+ return;
+ }
+
+ int hours = ui->recordingTimerHours->value();
+ int minutes = ui->recordingTimerMinutes->value();
+ int seconds = ui->recordingTimerSeconds->value();
+
+ int total = (((hours * 3600) +
+ (minutes * 60)) +
+ seconds) * 1000;
+
+ if (total == 0)
+ total = 1000;
+
+ recordingTimer->setInterval(total);
+ recordingTimer->setSingleShot(true);
+
+ QObject::connect(recordingTimer, SIGNAL(timeout()),
+ SLOT(EventStopRecording()));
+
+ QObject::connect(recordingTimerDisplay, SIGNAL(timeout()), this,
+ SLOT(UpdateRecordTimerDisplay()));
+
+ recordingTimer->start();
+ recordingTimerDisplay->start(1000);
+ ui->outputTimerRecord->setText(obs_module_text("Stop"));
+
+ UpdateRecordTimerDisplay();
+}
+
+void OutputTimer::StreamTimerStop()
+{
+ streamingAlreadyActive = false;
+
+ if (!isVisible() && streamingTimer->isActive() == false)
+ return;
+
+ if (streamingTimer->isActive())
+ streamingTimer->stop();
+
+ ui->outputTimerStream->setText(obs_module_text("Start"));
+
+ if (streamingTimerDisplay->isActive())
+ streamingTimerDisplay->stop();
+
+ ui->streamTime->setText("00:00:00");
+}
+
+void OutputTimer::RecordTimerStop()
+{
+ recordingAlreadyActive = false;
+
+ if (!isVisible() && recordingTimer->isActive() == false)
+ return;
+
+ if (recordingTimer->isActive())
+ recordingTimer->stop();
+
+ ui->outputTimerRecord->setText(obs_module_text("Start"));
+
+ if (recordingTimerDisplay->isActive())
+ recordingTimerDisplay->stop();
+
+ ui->recordTime->setText("00:00:00");
+}
+
+void OutputTimer::UpdateStreamTimerDisplay()
+{
+ int remainingTime = streamingTimer->remainingTime() / 1000;
+
+ int seconds = remainingTime % 60;
+ int minutes = (remainingTime % 3600) / 60;
+ int hours = remainingTime / 3600;
+
+ QString text;
+ text.sprintf("%02d:%02d:%02d", hours, minutes, seconds);
+ ui->streamTime->setText(text);
+}
+
+void OutputTimer::UpdateRecordTimerDisplay()
+{
+ int remainingTime = recordingTimer->remainingTime() / 1000;
+
+ int seconds = remainingTime % 60;
+ int minutes = (remainingTime % 3600) / 60;
+ int hours = remainingTime / 3600;
+
+ QString text;
+ text.sprintf("%02d:%02d:%02d", hours, minutes, seconds);
+ ui->recordTime->setText(text);
+}
+
+void OutputTimer::ShowHideDialog()
+{
+ if (!isVisible()) {
+ setVisible(true);
+ QTimer::singleShot(250, this, SLOT(show()));
+ } else {
+ setVisible(false);
+ QTimer::singleShot(250, this, SLOT(hide()));
+ }
+}
+
+void OutputTimer::EventStopStreaming()
+{
+ obs_frontend_streaming_stop();
+}
+
+void OutputTimer::EventStopRecording()
+{
+ obs_frontend_recording_stop();
+}
+
+static void SaveOutputTimer(obs_data_t *save_data, bool saving, void *)
+{
+ if (saving) {
+ obs_data_t *obj = obs_data_create();
+
+ obs_data_set_int(obj, "streamTimerHours",
+ ot->ui->streamingTimerHours->value());
+ obs_data_set_int(obj, "streamTimerMinutes",
+ ot->ui->streamingTimerMinutes->value());
+ obs_data_set_int(obj, "streamTimerSeconds",
+ ot->ui->streamingTimerSeconds->value());
+
+ obs_data_set_int(obj, "recordTimerHours",
+ ot->ui->recordingTimerHours->value());
+ obs_data_set_int(obj, "recordTimerMinutes",
+ ot->ui->recordingTimerMinutes->value());
+ obs_data_set_int(obj, "recordTimerSeconds",
+ ot->ui->recordingTimerSeconds->value());
+
+ obs_data_set_bool(obj, "autoStartStreamTimer",
+ ot->ui->autoStartStreamTimer->isChecked());
+ obs_data_set_bool(obj, "autoStartRecordTimer",
+ ot->ui->autoStartRecordTimer->isChecked());
+
+ obs_data_set_obj(save_data, "output-timer", obj);
+
+ obs_data_release(obj);
+ } else {
+ obs_data_t *obj = obs_data_get_obj(save_data,
+ "output-timer");
+
+ if (!obj)
+ obj = obs_data_create();
+
+ ot->ui->streamingTimerHours->setValue(
+ obs_data_get_int(obj, "streamTimerHours"));
+ ot->ui->streamingTimerMinutes->setValue(
+ obs_data_get_int(obj, "streamTimerMinutes"));
+ ot->ui->streamingTimerSeconds->setValue(
+ obs_data_get_int(obj, "streamTimerSeconds"));
+
+ ot->ui->recordingTimerHours->setValue(
+ obs_data_get_int(obj, "recordTimerHours"));
+ ot->ui->recordingTimerMinutes->setValue(
+ obs_data_get_int(obj, "recordTimerMinutes"));
+ ot->ui->recordingTimerSeconds->setValue(
+ obs_data_get_int(obj, "recordTimerSeconds"));
+
+ ot->ui->autoStartStreamTimer->setChecked(
+ obs_data_get_bool(obj, "autoStartStreamTimer"));
+ ot->ui->autoStartRecordTimer->setChecked(
+ obs_data_get_bool(obj, "autoStartRecordTimer"));
+
+ obs_data_release(obj);
+ }
+}
+
+extern "C" void FreeOutputTimer()
+{
+}
+
+static void OBSEvent(enum obs_frontend_event event, void *)
+{
+ if (event == OBS_FRONTEND_EVENT_EXIT) {
+ obs_frontend_save();
+ FreeOutputTimer();
+ } else if (event == OBS_FRONTEND_EVENT_STREAMING_STARTED) {
+ ot->StreamTimerStart();
+ } else if (event == OBS_FRONTEND_EVENT_STREAMING_STOPPING) {
+ ot->StreamTimerStop();
+ } else if (event == OBS_FRONTEND_EVENT_RECORDING_STARTED) {
+ ot->RecordTimerStart();
+ } else if (event == OBS_FRONTEND_EVENT_RECORDING_STOPPING) {
+ ot->RecordTimerStop();
+ }
+}
+
+extern "C" void InitOutputTimer()
+{
+ QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
+ obs_module_text("OutputTimer"));
+
+ obs_frontend_push_ui_translation(obs_module_get_string);
+
+ QMainWindow *window = (QMainWindow*)obs_frontend_get_main_window();
+
+ ot = new OutputTimer(window);
+
+ auto cb = [] ()
+ {
+ ot->ShowHideDialog();
+ };
+
+ obs_frontend_pop_ui_translation();
+
+ obs_frontend_add_save_callback(SaveOutputTimer, nullptr);
+ obs_frontend_add_event_callback(OBSEvent, nullptr);
+
+ action->connect(action, &QAction::triggered, cb);
+}
diff --git a/UI/frontend-plugins/frontend-tools/output-timer.hpp b/UI/frontend-plugins/frontend-tools/output-timer.hpp
new file mode 100644
index 0000000..ff3b733
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/output-timer.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include
+#include
+
+#include "ui_output-timer.h"
+
+class QCloseEvent;
+
+class OutputTimer : public QDialog {
+ Q_OBJECT
+
+public:
+ std::unique_ptr ui;
+ OutputTimer(QWidget *parent);
+
+ void closeEvent(QCloseEvent *event) override;
+
+public slots:
+ void StreamingTimerButton();
+ void RecordingTimerButton();
+ void StreamTimerStart();
+ void RecordTimerStart();
+ void StreamTimerStop();
+ void RecordTimerStop();
+ void UpdateStreamTimerDisplay();
+ void UpdateRecordTimerDisplay();
+ void ShowHideDialog();
+ void EventStopStreaming();
+ void EventStopRecording();
+
+private:
+ bool streamingAlreadyActive = false;
+ bool recordingAlreadyActive = false;
+
+ QTimer *streamingTimer;
+ QTimer *recordingTimer;
+ QTimer *streamingTimerDisplay;
+ QTimer *recordingTimerDisplay;
+};
diff --git a/UI/frontend-plugins/frontend-tools/tool-helpers.hpp b/UI/frontend-plugins/frontend-tools/tool-helpers.hpp
new file mode 100644
index 0000000..840e746
--- /dev/null
+++ b/UI/frontend-plugins/frontend-tools/tool-helpers.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include
+#include
+#include
+
+static inline OBSWeakSource GetWeakSourceByName(const char *name)
+{
+ OBSWeakSource weak;
+ obs_source_t *source = obs_get_source_by_name(name);
+ if (source) {
+ weak = obs_source_get_weak_source(source);
+ obs_weak_source_release(weak);
+ obs_source_release(source);
+ }
+
+ return weak;
+}
+
+static inline OBSWeakSource GetWeakSourceByQString(const QString &name)
+{
+ return GetWeakSourceByName(name.toUtf8().constData());
+}
+
+static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source)
+{
+ std::string name;
+
+ obs_source_t *source = obs_weak_source_get_source(weak_source);
+ if (source) {
+ name = obs_source_get_name(source);
+ obs_source_release(source);
+ }
+
+ return name;
+}
diff --git a/UI/installer/mp-installer.nsi b/UI/installer/mp-installer.nsi
index 28c2229..23480b1 100644
--- a/UI/installer/mp-installer.nsi
+++ b/UI/installer/mp-installer.nsi
@@ -1,10 +1,18 @@
; Script generated with the Venis Install Wizard
+Unicode true
+
; Define your application name
!define APPNAME "OBS Studio"
-!define APPVERSION "0.13.4"
-!define APPNAMEANDVERSION "OBS Studio ${APPVERSION}"
-; !define BROWSER
+
+!ifndef APPVERSION
+!define APPVERSION "17.0.2"
+!define SHORTVERSION "17.0.2"
+!endif
+
+!define APPNAMEANDVERSION "OBS Studio ${SHORTVERSION}"
+; !define FULL
+!define REALSENSE_PLUGIN
; Additional script dependencies
!include WinVer.nsh
@@ -14,10 +22,10 @@
Name "${APPNAMEANDVERSION}"
InstallDir "$PROGRAMFILES32\obs-studio"
InstallDirRegKey HKLM "Software\${APPNAME}" ""
-!ifdef BROWSER
-OutFile "OBS-Studio-${APPVERSION}-With-Browser-Installer.exe"
+!ifdef FULL
+OutFile "OBS-Studio-${SHORTVERSION}-Full-Installer.exe"
!else
-OutFile "OBS-Studio-${APPVERSION}-Installer.exe"
+OutFile "OBS-Studio-${SHORTVERSION}-Small-Installer.exe"
!endif
; Use compression
@@ -30,13 +38,18 @@ RequestExecutionLevel admin
!include "MUI.nsh"
!define MUI_ABORTWARNING
-!define MUI_FINISHPAGE_RUN "$INSTDIR\bin\32bit\obs32.exe"
+!define MUI_FINISHPAGE_RUN
+!define MUI_FINISHPAGE_RUN_TEXT "Launch OBS Studio ${SHORTVERSION}"
+!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchOBS"
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE PreReqCheck
!insertmacro MUI_PAGE_WELCOME
-!insertmacro MUI_PAGE_LICENSE "data\obs-studio\license\gplv2.txt"
+!insertmacro MUI_PAGE_LICENSE "new\core\data\obs-studio\license\gplv2.txt"
!insertmacro MUI_PAGE_DIRECTORY
+!ifdef FULL
+ !insertmacro MUI_PAGE_COMPONENTS
+!endif
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
@@ -156,51 +169,68 @@ Function PreReqCheck
ClearErrors
; Check previous instance
- FindProcDLL::FindProc "obs32.exe"
+
+ OBSInstallerUtils::IsProcessRunning "obs32.exe"
IntCmp $R0 1 0 notRunning1
MessageBox MB_OK|MB_ICONEXCLAMATION "${APPNAME} is already running. Please close it first before installing a new version." /SD IDOK
Quit
notRunning1:
+
${if} ${RunningX64}
- FindProcDLL::FindProc "obs64.exe"
+ OBSInstallerUtils::IsProcessRunning "obs64.exe"
IntCmp $R0 1 0 notRunning2
MessageBox MB_OK|MB_ICONEXCLAMATION "${APPNAME} is already running. Please close it first before installing a new version." /SD IDOK
Quit
+ notRunning2:
${endif}
- notRunning2:
+ OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook32.dll"
+ OBSInstallerUtils::AddInUseFileCheck "$INSTDIR\data\obs-plugins\win-capture\graphics-hook64.dll"
+ OBSInstallerUtils::GetAppNameForInUseFiles
+ StrCmp $R0 "" gameCaptureNotRunning
+ MessageBox MB_OK|MB_ICONEXCLAMATION "Game Capture is still in use by the following applications:$\r$\n$\r$\n$R0$\r$\nPlease close these applications before installing a new version of OBS." /SD IDOK
+ Quit
+ gameCaptureNotRunning:
FunctionEnd
Function filesInUse
MessageBox MB_OK|MB_ICONEXCLAMATION "Some files were not able to be installed. If this is the first time you are installing OBS, please disable any anti-virus or other security software and try again. If you are re-installing or updating OBS, close any applications that may be have been hooked, or reboot and try again." /SD IDOK
FunctionEnd
+Function LaunchOBS
+ ${if} ${RunningX64}
+ Exec '"$WINDIR\explorer.exe" "$SMPROGRAMS\OBS Studio\OBS Studio (64bit).lnk"'
+ ${else}
+ Exec '"$WINDIR\explorer.exe" "$SMPROGRAMS\OBS Studio\OBS Studio (32bit).lnk"'
+ ${endif}
+FunctionEnd
+
Var outputErrors
-Section "OBS Studio" Section1
+Section "OBS Studio" SecCore
; Set Section properties
+ SectionIn RO
SetOverwrite on
AllowSkipFiles off
- FindProcDLL::KillProc "obs-plugins\32bit\cef-bootstrap.exe"
- FindProcDLL::KillProc "obs-plugins\64bit\cef-bootstrap.exe"
-
SetShellVarContext all
; Set Section Files and Shortcuts
SetOutPath "$INSTDIR"
- File /r "data"
+ OBSInstallerUtils::KillProcess "obs-plugins\32bit\cef-bootstrap.exe"
+ OBSInstallerUtils::KillProcess "obs-plugins\64bit\cef-bootstrap.exe"
+ File /r "new\core\data"
SetOutPath "$INSTDIR\bin"
- File /r "bin\32bit"
+ File /r "new\core\bin\32bit"
SetOutPath "$INSTDIR\obs-plugins"
- File /r "obs-plugins\32bit"
+ File /r "new\core\obs-plugins\32bit"
${if} ${RunningX64}
SetOutPath "$INSTDIR\bin"
- File /r "bin\64bit"
+ File /r "new\core\bin\64bit"
SetOutPath "$INSTDIR\obs-plugins"
- File /r "obs-plugins\64bit"
+ File /r "new\core\obs-plugins\64bit"
${endif}
ClearErrors
@@ -218,8 +248,14 @@ Section "OBS Studio" Section1
Delete "$SMPROGRAMS\OBS Multiplatform\OBS Multiplatform (64bit).lnk"
${endif}
+ ${if} ${RunningX64}
+ SetOutPath "$INSTDIR\bin\64bit"
+ CreateShortCut "$DESKTOP\OBS Studio.lnk" "$INSTDIR\bin\64bit\obs64.exe"
+ ${else}
+ SetOutPath "$INSTDIR\bin\32bit"
+ CreateShortCut "$DESKTOP\OBS Studio.lnk" "$INSTDIR\bin\32bit\obs32.exe"
+ ${endif}
SetOutPath "$INSTDIR\bin\32bit"
- CreateShortCut "$DESKTOP\OBS Studio.lnk" "$INSTDIR\bin\32bit\obs32.exe"
CreateDirectory "$SMPROGRAMS\OBS Studio"
CreateShortCut "$SMPROGRAMS\OBS Studio\OBS Studio (32bit).lnk" "$INSTDIR\bin\32bit\obs32.exe"
CreateShortCut "$SMPROGRAMS\OBS Studio\Uninstall.lnk" "$INSTDIR\uninstall.exe"
@@ -235,6 +271,64 @@ Section "OBS Studio" Section1
Call filesInUse
SectionEnd
+!ifdef FULL
+SectionGroup /e "Plugins" SecPlugins
+ Section "Browser plugin" SecPlugins_Browser
+ ; Set Section properties
+ SetOverwrite on
+ AllowSkipFiles off
+ SetShellVarContext all
+
+ SetOutPath "$INSTDIR\obs-plugins"
+ OBSInstallerUtils::KillProcess "32bit\cef-bootstrap.exe"
+ File /r "new\obs-browser\obs-plugins\32bit"
+
+ ${if} ${RunningX64}
+ OBSInstallerUtils::KillProcess "64bit\cef-bootstrap.exe"
+ File /r "new\obs-browser\obs-plugins\64bit"
+ ${endif}
+
+ SetOutPath "$INSTDIR\bin\32bit"
+ SectionEnd
+
+ !ifdef REALSENSE_PLUGIN
+ Section /o "Realsense plugin" SecPlugins_Realsense
+ SetOverwrite on
+ AllowSkipFiles off
+ SetShellVarContext all
+
+ SetOutPath "$INSTDIR\obs-plugins"
+ File /r "new\realsense\32bit"
+
+ ${if} ${RunningX64}
+ File /r "new\realsense\64bit"
+ ${endif}
+
+ SetOutPath "$INSTDIR\data\obs-plugins"
+ File /r "new\realsense\data\obs-plugins\win-ivcam"
+
+ ExecWait '"$INSTDIR\data\obs-plugins\win-ivcam\seg_service.exe" /UnregServer'
+ ExecWait '"$INSTDIR\data\obs-plugins\win-ivcam\seg_service.exe" /RegServer'
+
+ ReadRegStr $0 HKLM "Software\Intel\RSSDK\Dispatch" "Core"
+ ${if} ${Errors}
+ ReadRegStr $0 HKLM "Software\Intel\RSSDK\v10\Dispatch" "Core"
+ ${endif}
+
+ ${if} ${Errors}
+ InitPluginsDir
+ SetOutPath "$PLUGINSDIR\realsense"
+
+ File "intel_rs_sdk_runtime_websetup_10.0.26.0396.exe"
+ ExecWait '"$PLUGINSDIR\realsense\intel_rs_sdk_runtime_websetup_10.0.26.0396.exe" --finstall=personify --fnone=all'
+ ${endif}
+
+ SetOutPath "$INSTDIR\bin\32bit"
+ SectionEnd
+ !endif
+SectionGroupEnd
+!endif
+
Section -FinishSection
WriteRegStr HKLM "Software\${APPNAME}" "" "$INSTDIR"
@@ -250,11 +344,18 @@ SectionEnd
; Modern install component descriptions
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
- !insertmacro MUI_DESCRIPTION_TEXT ${Section1} ""
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecCore} "Core OBS Studio files"
+ !ifdef FULL
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecPlugins} "Optional Plugins"
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecPlugins_Browser} "Browser plugin (a source you can add to your scenes that displays web pages)"
+ !ifdef REALSENSE_PLUGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecPlugins_Realsense} "Plugin for Realsense cameras"
+ !endif
+ !endif
!insertmacro MUI_FUNCTION_DESCRIPTION_END
;Uninstall section
-Section "un.obs-studio Program Files"
+Section "un.obs-studio Program Files" UninstallSection1
SectionIn RO
@@ -273,6 +374,11 @@ Section "un.obs-studio Program Files"
Delete "$SMPROGRAMS\OBS Studio\OBS Studio (64bit).lnk"
${endif}
+ IfFileExists "$INSTDIR\data\obs-plugins\win-ivcam\seg_service.exe" UnregisterSegService SkipUnreg
+ UnregisterSegService:
+ ExecWait '"$INSTDIR\data\obs-plugins\win-ivcam\seg_service.exe" /UnregServer'
+ SkipUnreg:
+
; Clean up OBS Studio
RMDir /r "$INSTDIR\bin"
RMDir /r "$INSTDIR\data"
@@ -284,17 +390,17 @@ Section "un.obs-studio Program Files"
RMDir "$INSTDIR\OBS Studio"
SectionEnd
-Section /o "un.User Settings" Section2
+Section /o "un.User Settings" UninstallSection2
RMDir /R "$APPDATA\obs-studio"
SectionEnd
!insertmacro MUI_UNFUNCTION_DESCRIPTION_BEGIN
- !insertmacro MUI_DESCRIPTION_TEXT ${Section1} "Remove the OBS program files."
- !insertmacro MUI_DESCRIPTION_TEXT ${Section2} "Removes all settings, plugins, scenes and sources, profiles, log files and other application data."
+ !insertmacro MUI_DESCRIPTION_TEXT ${UninstallSection1} "Remove the OBS program files."
+ !insertmacro MUI_DESCRIPTION_TEXT ${UninstallSection2} "Removes all settings, plugins, scenes and sources, profiles, log files and other application data."
!insertmacro MUI_UNFUNCTION_DESCRIPTION_END
; Version information
-VIProductVersion "0.${APPVERSION}"
+VIProductVersion "${APPVERSION}.0"
VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "OBS Studio"
VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "obsproject.com"
VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "(c) 2012-2016"
diff --git a/UI/obs-app.cpp b/UI/obs-app.cpp
index e7bb8f6..d233d77 100644
--- a/UI/obs-app.cpp
+++ b/UI/obs-app.cpp
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -29,7 +30,9 @@
#include
#include
+#include
#include
+#include
#include "qt-wrappers.hpp"
#include "obs-app.hpp"
@@ -49,6 +52,8 @@
#include
#endif
+#include
+
using namespace std;
static log_handler_t def_log_handler;
@@ -57,12 +62,22 @@ static string currentLogFile;
static string lastLogFile;
static bool portable_mode = false;
+static bool log_verbose = false;
+static bool unfiltered_log = false;
bool opt_start_streaming = false;
bool opt_start_recording = false;
+bool opt_studio_mode = false;
+bool opt_start_replaybuffer = false;
+bool opt_minimize_tray = false;
string opt_starting_collection;
string opt_starting_profile;
string opt_starting_scene;
+// AMD PowerXpress High Performance Flags
+#ifdef _MSC_VER
+extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+#endif
+
QObject *CreateShortcutFilter()
{
return new OBSEventFilter([](QObject *obj, QEvent *event)
@@ -268,6 +283,10 @@ static inline bool too_many_repeated_entries(fstream &logFile, const char *msg,
lock_guard guard(log_mutex);
+ if (unfiltered_log) {
+ return false;
+ }
+
if (last_msg_ptr == msg) {
int diff = std::abs(new_sum - last_char_sum);
if (diff < MAX_CHAR_VARIATION) {
@@ -303,8 +322,22 @@ static void do_log(int log_level, const char *msg, va_list args, void *param)
vsnprintf(str, 4095, msg, args);
#ifdef _WIN32
- OutputDebugStringA(str);
- OutputDebugStringA("\n");
+ if (IsDebuggerPresent()) {
+ int wNum = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ if (wNum > 1) {
+ static wstring wide_buf;
+ static mutex wide_mutex;
+
+ lock_guard lock(wide_mutex);
+ wide_buf.reserve(wNum + 1);
+ wide_buf.resize(wNum - 1);
+ MultiByteToWideChar(CP_UTF8, 0, str, -1, &wide_buf[0],
+ wNum);
+ wide_buf.push_back('\n');
+
+ OutputDebugStringW(wide_buf.c_str());
+ }
+ }
#else
def_log_handler(log_level, msg, args2, nullptr);
#endif
@@ -312,7 +345,7 @@ static void do_log(int log_level, const char *msg, va_list args, void *param)
if (too_many_repeated_entries(logFile, msg, str))
return;
- if (log_level <= LOG_INFO)
+ if (log_level <= LOG_INFO || log_verbose)
LogStringChunk(logFile, str);
#if defined(_WIN32) && defined(OBS_DEBUGBREAK_ON_ERROR)
@@ -330,6 +363,8 @@ bool OBSApp::InitGlobalConfigDefaults()
config_set_default_uint(globalConfig, "General", "MaxLogs", 10);
config_set_default_string(globalConfig, "General", "ProcessPriority",
"Normal");
+ config_set_default_bool(globalConfig, "General", "EnableAutoUpdates",
+ true);
#if _WIN32
config_set_default_string(globalConfig, "Video", "Renderer",
@@ -364,6 +399,8 @@ bool OBSApp::InitGlobalConfigDefaults()
"SysTrayEnabled", true);
config_set_default_bool(globalConfig, "BasicWindow",
"SysTrayWhenStarted", false);
+ config_set_default_bool(globalConfig, "BasicWindow",
+ "SaveProjectors", false);
config_set_default_bool(globalConfig, "BasicWindow",
"ShowTransitions", true);
config_set_default_bool(globalConfig, "BasicWindow",
@@ -413,7 +450,13 @@ static bool MakeUserDirs()
return false;
if (!do_mkdir(path))
return false;
+
+ if (GetConfigPath(path, sizeof(path), "obs-studio/updates") <= 0)
+ return false;
+ if (!do_mkdir(path))
+ return false;
#endif
+
if (GetConfigPath(path, sizeof(path), "obs-studio/plugin_config") <= 0)
return false;
if (!do_mkdir(path))
@@ -448,7 +491,7 @@ static string GetProfileDirFromName(const char *name)
if (GetConfigPath(path, sizeof(path), "obs-studio/basic/profiles") <= 0)
return outputPath;
- strcat(path, "/*.*");
+ strcat(path, "/*");
if (os_glob(path, 0, &glob) != 0)
return outputPath;
@@ -855,6 +898,9 @@ bool OBSApp::OBSInit()
if (!StartupOBS(locale.c_str(), GetProfilerNameStore()))
return false;
+ blog(LOG_INFO, "Portable mode: %s",
+ portable_mode ? "true" : "false");
+
mainWindow = new OBSBasic();
mainWindow->setAttribute(Qt::WA_DeleteOnClose, true);
@@ -906,6 +952,11 @@ string OBSApp::GetVersionString() const
return ver.str();
}
+bool OBSApp::IsPortableMode()
+{
+ return portable_mode;
+}
+
#ifdef __APPLE__
#define INPUT_AUDIO_SOURCE "coreaudio_input_capture"
#define OUTPUT_AUDIO_SOURCE "coreaudio_output_capture"
@@ -1094,79 +1145,9 @@ string GenerateTimeDateFilename(const char *extension, bool noSpace)
string GenerateSpecifiedFilename(const char *extension, bool noSpace,
const char *format)
{
- time_t now = time(0);
- struct tm *cur_time;
- cur_time = localtime(&now);
-
- const size_t spec_count = 23;
- const char *spec[][2] = {
- {"%CCYY", "%Y"},
- {"%YY", "%y"},
- {"%MM", "%m"},
- {"%DD", "%d"},
- {"%hh", "%H"},
- {"%mm", "%M"},
- {"%ss", "%S"},
- {"%%", "%%"},
-
- {"%a", ""},
- {"%A", ""},
- {"%b", ""},
- {"%B", ""},
- {"%d", ""},
- {"%H", ""},
- {"%I", ""},
- {"%m", ""},
- {"%M", ""},
- {"%p", ""},
- {"%S", ""},
- {"%y", ""},
- {"%Y", ""},
- {"%z", ""},
- {"%Z", ""},
- };
-
- char convert[128] = {};
- string sf = format;
- string c;
- size_t pos = 0, len;
-
- while (pos < sf.length()) {
- len = 0;
- for (size_t i = 0; i < spec_count && len == 0; i++) {
-
- if (sf.find(spec[i][0], pos) == pos) {
- if (strlen(spec[i][1]))
- strftime(convert, sizeof(convert),
- spec[i][1], cur_time);
- else
- strftime(convert, sizeof(convert),
- spec[i][0], cur_time);
-
- len = strlen(spec[i][0]);
-
- c = convert;
- if (c.length() && c.find_first_not_of(' ') !=
- std::string::npos)
- sf.replace(pos, len, convert);
- }
- }
-
- if (len)
- pos += strlen(convert);
- else if (!len && sf.at(pos) == '%')
- sf.erase(pos,1);
- else
- pos++;
- }
-
- if (noSpace)
- replace(sf.begin(), sf.end(), ' ', '_');
-
- sf += '.';
- sf += extension;
-
- return (sf.length() < 256) ? sf : sf.substr(0, 255);
+ BPtr filename = os_generate_formatted_filename(extension,
+ !noSpace, format);
+ return string(filename);
}
vector> GetLocaleNames()
@@ -1291,20 +1272,6 @@ static int run_program(fstream &logFile, int argc, char *argv[])
profiler_start();
profile_register_root(run_program_init, 0);
- auto PrintInitProfile = [&]()
- {
- auto snap = GetSnapshot();
-
- profiler_snapshot_filter_roots(snap.get(), [](void *data,
- const char *name, bool *remove)
- {
- *remove = (*static_cast(data)) != name;
- return true;
- }, static_cast(&run_program_init));
-
- profiler_print(snap.get());
- };
-
ScopeProfiler prof{run_program_init};
QCoreApplication::addLibraryPath(".");
@@ -1520,20 +1487,10 @@ bool GetClosestUnusedFileName(std::string &path, const char *extension)
bool WindowPositionValid(QRect rect)
{
- vector monitors;
- GetMonitors(monitors);
-
- for (auto &monitor : monitors) {
- int left = int(monitor.x);
- int top = int(monitor.y);
- int right = left + int(monitor.cx);
- int bottom = top + int(monitor.cy);
-
- if ((rect.left() - right) < 0 && (left - rect.right()) < 0 &&
- (rect.top() - bottom) < 0 && (top - rect.bottom()) < 0)
+ for (QScreen* screen: QGuiApplication::screens()) {
+ if (screen->availableGeometry().intersects(rect))
return true;
}
-
return false;
}
@@ -1796,12 +1753,21 @@ int main(int argc, char *argv[])
if (arg_is(argv[i], "--portable", "-p")) {
portable_mode = true;
+ } else if (arg_is(argv[i], "--verbose", nullptr)) {
+ log_verbose = true;
+
+ } else if (arg_is(argv[i], "--unfiltered_log", nullptr)) {
+ unfiltered_log = true;
+
} else if (arg_is(argv[i], "--startstreaming", nullptr)) {
opt_start_streaming = true;
} else if (arg_is(argv[i], "--startrecording", nullptr)) {
opt_start_recording = true;
+ } else if (arg_is(argv[i], "--startreplaybuffer", nullptr)) {
+ opt_start_replaybuffer = true;
+
} else if (arg_is(argv[i], "--collection", nullptr)) {
if (++i < argc) opt_starting_collection = argv[i];
@@ -1810,6 +1776,36 @@ int main(int argc, char *argv[])
} else if (arg_is(argv[i], "--scene", nullptr)) {
if (++i < argc) opt_starting_scene = argv[i];
+
+ } else if (arg_is(argv[i], "--minimize-to-tray", nullptr)) {
+ opt_minimize_tray = true;
+
+ } else if (arg_is(argv[i], "--studio-mode", nullptr)) {
+ opt_studio_mode = true;
+
+ } else if (arg_is(argv[i], "--help", "-h")) {
+ std::cout <<
+ "--help, -h: Get list of available commands.\n\n" <<
+ "--startstreaming: Automatically start streaming.\n" <<
+ "--startrecording: Automatically start recording.\n" <<
+ "--startreplaybuffer: Start replay buffer.\n\n" <<
+ "--collection : Use specific scene collection."
+ << "\n" <<
+ "--profile : Use specific profile.\n" <<
+ "--scene : Start with specific scene.\n\n" <<
+ "--studio-mode: Enable studio mode.\n" <<
+ "--minimize-to-tray: Minimize to system tray.\n" <<
+ "--portable, -p: Use portable mode.\n\n" <<
+ "--verbose: Make log more verbose.\n" <<
+ "--unfiltered_log: Make log unfiltered.\n\n" <<
+ "--version, -V: Get current version.\n";
+
+ exit(0);
+
+ } else if (arg_is(argv[i], "--version", "-V")) {
+ std::cout << "OBS Studio - " <<
+ App()->GetVersionString() << "\n";
+ exit(0);
}
}
diff --git a/UI/obs-app.hpp b/UI/obs-app.hpp
index 9c45803..381f9d6 100644
--- a/UI/obs-app.hpp
+++ b/UI/obs-app.hpp
@@ -117,6 +117,7 @@ public:
const char *GetCurrentLog() const;
std::string GetVersionString() const;
+ bool IsPortableMode();
const char *InputAudioSource() const;
const char *OutputAudioSource() const;
@@ -177,4 +178,7 @@ static inline int GetProfilePath(char *path, size_t size, const char *file)
extern bool opt_start_streaming;
extern bool opt_start_recording;
+extern bool opt_start_replaybuffer;
+extern bool opt_minimize_tray;
+extern bool opt_studio_mode;
extern std::string opt_starting_scene;
diff --git a/UI/obs-frontend-api/CMakeLists.txt b/UI/obs-frontend-api/CMakeLists.txt
index 38eefb6..1d5ca9a 100644
--- a/UI/obs-frontend-api/CMakeLists.txt
+++ b/UI/obs-frontend-api/CMakeLists.txt
@@ -17,4 +17,13 @@ add_library(obs-frontend-api SHARED
target_link_libraries(obs-frontend-api
libobs)
+if(UNIX AND NOT APPLE)
+ set_target_properties(obs-frontend-api
+ PROPERTIES
+ OUTPUT_NAME obs-frontend-api
+ VERSION 0.0
+ SOVERSION 0
+ )
+endif()
+
install_obs_core(obs-frontend-api)
diff --git a/UI/obs-frontend-api/obs-frontend-api.cpp b/UI/obs-frontend-api/obs-frontend-api.cpp
index 5d01b64..6951bc9 100644
--- a/UI/obs-frontend-api/obs-frontend-api.cpp
+++ b/UI/obs-frontend-api/obs-frontend-api.cpp
@@ -205,6 +205,23 @@ bool obs_frontend_recording_active(void)
: false;
}
+void obs_frontend_replay_buffer_start(void)
+{
+ if (callbacks_valid()) c->obs_frontend_replay_buffer_start();
+}
+
+void obs_frontend_replay_buffer_stop(void)
+{
+ if (callbacks_valid()) c->obs_frontend_replay_buffer_stop();
+}
+
+bool obs_frontend_replay_buffer_active(void)
+{
+ return !!callbacks_valid()
+ ? c->obs_frontend_replay_buffer_active()
+ : false;
+}
+
void *obs_frontend_add_tools_menu_qaction(const char *name)
{
return !!callbacks_valid()
@@ -248,6 +265,13 @@ obs_output_t *obs_frontend_get_recording_output(void)
: nullptr;
}
+obs_output_t *obs_frontend_get_replay_buffer_output(void)
+{
+ return !!callbacks_valid()
+ ? c->obs_frontend_get_replay_buffer_output()
+ : nullptr;
+}
+
config_t *obs_frontend_get_profile_config(void)
{
return !!callbacks_valid()
diff --git a/UI/obs-frontend-api/obs-frontend-api.h b/UI/obs-frontend-api/obs-frontend-api.h
index 8a6272a..7be113c 100644
--- a/UI/obs-frontend-api/obs-frontend-api.h
+++ b/UI/obs-frontend-api/obs-frontend-api.h
@@ -70,6 +70,10 @@ EXPORT void obs_frontend_recording_start(void);
EXPORT void obs_frontend_recording_stop(void);
EXPORT bool obs_frontend_recording_active(void);
+EXPORT void obs_frontend_replay_buffer_start(void);
+EXPORT void obs_frontend_replay_buffer_stop(void);
+EXPORT bool obs_frontend_replay_buffer_active(void);
+
typedef void (*obs_frontend_cb)(void *private_data);
EXPORT void *obs_frontend_add_tools_menu_qaction(const char *name);
@@ -94,7 +98,12 @@ enum obs_frontend_event {
OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED,
OBS_FRONTEND_EVENT_PROFILE_CHANGED,
OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED,
- OBS_FRONTEND_EVENT_EXIT
+ OBS_FRONTEND_EVENT_EXIT,
+
+ OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING,
+ OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED,
+ OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING,
+ OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED
};
typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event,
@@ -116,6 +125,7 @@ EXPORT void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
EXPORT obs_output_t *obs_frontend_get_streaming_output(void);
EXPORT obs_output_t *obs_frontend_get_recording_output(void);
+EXPORT obs_output_t *obs_frontend_get_replay_buffer_output(void);
EXPORT config_t *obs_frontend_get_profile_config(void);
EXPORT config_t *obs_frontend_get_global_config(void);
diff --git a/UI/obs-frontend-api/obs-frontend-internal.hpp b/UI/obs-frontend-api/obs-frontend-internal.hpp
index cb8da96..5784eeb 100644
--- a/UI/obs-frontend-api/obs-frontend-internal.hpp
+++ b/UI/obs-frontend-api/obs-frontend-internal.hpp
@@ -6,6 +6,7 @@
#include
struct obs_frontend_callbacks {
+ virtual ~obs_frontend_callbacks() {}
virtual void *obs_frontend_get_main_window(void)=0;
virtual void *obs_frontend_get_main_window_handle(void)=0;
@@ -39,6 +40,10 @@ struct obs_frontend_callbacks {
virtual void obs_frontend_recording_stop(void)=0;
virtual bool obs_frontend_recording_active(void)=0;
+ virtual void obs_frontend_replay_buffer_start(void)=0;
+ virtual void obs_frontend_replay_buffer_stop(void)=0;
+ virtual bool obs_frontend_replay_buffer_active(void)=0;
+
virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0;
virtual void obs_frontend_add_tools_menu_item(const char *name,
obs_frontend_cb callback, void *private_data)=0;
@@ -50,6 +55,7 @@ struct obs_frontend_callbacks {
virtual obs_output_t *obs_frontend_get_streaming_output(void)=0;
virtual obs_output_t *obs_frontend_get_recording_output(void)=0;
+ virtual obs_output_t *obs_frontend_get_replay_buffer_output(void)=0;
virtual config_t *obs_frontend_get_profile_config(void)=0;
virtual config_t *obs_frontend_get_global_config(void)=0;
diff --git a/UI/platform-osx.mm b/UI/platform-osx.mm
index d60f8ab..19b1a9c 100644
--- a/UI/platform-osx.mm
+++ b/UI/platform-osx.mm
@@ -36,17 +36,6 @@ bool GetDataFilePath(const char *data, string &output)
return !access(output.c_str(), R_OK);
}
-void GetMonitors(vector &monitors)
-{
- monitors.clear();
- for(NSScreen *screen : [NSScreen screens])
- {
- NSRect frame = [screen convertRectToBacking:[screen frame]];
- monitors.emplace_back(frame.origin.x, frame.origin.y,
- frame.size.width, frame.size.height);
- }
-}
-
bool InitApplicationBundle()
{
#ifdef OBS_OSX_BUNDLE
diff --git a/UI/platform-windows.cpp b/UI/platform-windows.cpp
index 8edde6e..7386375 100644
--- a/UI/platform-windows.cpp
+++ b/UI/platform-windows.cpp
@@ -51,28 +51,6 @@ bool GetDataFilePath(const char *data, string &output)
return check_path(data, OBS_DATA_PATH "/obs-studio/", output);
}
-static BOOL CALLBACK OBSMonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor,
- LPRECT rect, LPARAM param)
-{
- vector &monitors = *(vector *)param;
-
- monitors.emplace_back(
- rect->left,
- rect->top,
- rect->right - rect->left,
- rect->bottom - rect->top);
-
- UNUSED_PARAMETER(hMonitor);
- UNUSED_PARAMETER(hdcMonitor);
- return true;
-}
-
-void GetMonitors(vector &monitors)
-{
- monitors.clear();
- EnumDisplayMonitors(NULL, NULL, OBSMonitorEnumProc, (LPARAM)&monitors);
-}
-
bool InitApplicationBundle()
{
return true;
diff --git a/UI/platform-x11.cpp b/UI/platform-x11.cpp
index 1cca5da..c6b02b9 100644
--- a/UI/platform-x11.cpp
+++ b/UI/platform-x11.cpp
@@ -16,16 +16,12 @@
along with this program. If not, see .
******************************************************************************/
-/* Here we use xinerama to fetch data about monitor geometry
- * Even if there are not multiple monitors, this should still work.
- */
-
#include
#include "obs-app.hpp"
-#include
-#include
-#include
+#include
+#include
+
#include
#include
#include
@@ -63,59 +59,6 @@ bool GetDataFilePath(const char *data, string &output)
return false;
}
-void GetMonitors(vector &monitors)
-{
- xcb_connection_t* xcb_conn;
-
- monitors.clear();
- xcb_conn = xcb_connect(NULL, NULL);
-
- bool use_xinerama = false;
- if (xcb_get_extension_data(xcb_conn, &xcb_xinerama_id)->present) {
- xcb_xinerama_is_active_cookie_t xinerama_cookie;
- xcb_xinerama_is_active_reply_t* xinerama_reply = NULL;
-
- xinerama_cookie = xcb_xinerama_is_active(xcb_conn);
- xinerama_reply = xcb_xinerama_is_active_reply(xcb_conn,
- xinerama_cookie, NULL);
-
- if (xinerama_reply && xinerama_reply->state != 0)
- use_xinerama = true;
- free(xinerama_reply);
- }
-
- if (use_xinerama) {
- xcb_xinerama_query_screens_cookie_t screens_cookie;
- xcb_xinerama_query_screens_reply_t* screens_reply = NULL;
- xcb_xinerama_screen_info_iterator_t iter;
-
- screens_cookie = xcb_xinerama_query_screens(xcb_conn);
- screens_reply = xcb_xinerama_query_screens_reply(xcb_conn,
- screens_cookie, NULL);
- iter = xcb_xinerama_query_screens_screen_info_iterator(
- screens_reply);
-
- for(; iter.rem; xcb_xinerama_screen_info_next(&iter)) {
- monitors.emplace_back(iter.data->x_org,
- iter.data->y_org,
- iter.data->width,
- iter.data->height);
- }
- free(screens_reply);
- } else {
- // no xinerama so fall back to basic x11 calls
- xcb_screen_iterator_t iter;
-
- iter = xcb_setup_roots_iterator(xcb_get_setup(xcb_conn));
- for(; iter.rem; xcb_screen_next(&iter)) {
- monitors.emplace_back(0,0,iter.data->width_in_pixels,
- iter.data->height_in_pixels);
- }
- }
-
- xcb_disconnect(xcb_conn);
-}
-
bool InitApplicationBundle()
{
return true;
diff --git a/UI/platform.hpp b/UI/platform.hpp
index ad579d6..1b1344b 100644
--- a/UI/platform.hpp
+++ b/UI/platform.hpp
@@ -24,19 +24,8 @@
class QWidget;
-struct MonitorInfo {
- int32_t x, y;
- uint32_t cx, cy;
-
- inline MonitorInfo() {}
- inline MonitorInfo(int32_t x, int32_t y, uint32_t cx, uint32_t cy)
- : x(x), y(y), cx(cx), cy(cy)
- {}
-};
-
/* Gets the path of obs-studio specific data files (such as locale) */
bool GetDataFilePath(const char *data, std::string &path);
-void GetMonitors(std::vector &monitors);
/* Updates the working directory for OSX application bundles */
bool InitApplicationBundle();
diff --git a/UI/remote-text.cpp b/UI/remote-text.cpp
index b77a802..e4b5c39 100644
--- a/UI/remote-text.cpp
+++ b/UI/remote-text.cpp
@@ -22,6 +22,9 @@
using namespace std;
+static auto curl_deleter = [] (CURL *curl) {curl_easy_cleanup(curl);};
+using Curl = unique_ptr;
+
static size_t string_write(char *ptr, size_t size, size_t nmemb, string &str)
{
size_t total = size * nmemb;
@@ -45,9 +48,6 @@ void RemoteTextThread::run()
contentTypeString += contentType;
}
- auto curl_deleter = [] (CURL *curl) {curl_easy_cleanup(curl);};
- using Curl = unique_ptr;
-
Curl curl{curl_easy_init(), curl_deleter};
if (curl) {
struct curl_slist *header = nullptr;
@@ -91,3 +91,110 @@ void RemoteTextThread::run()
curl_slist_free_all(header);
}
}
+
+static size_t header_write(char *ptr, size_t size, size_t nmemb,
+ vector &list)
+{
+ string str;
+
+ size_t total = size * nmemb;
+ if (total)
+ str.append(ptr, total);
+
+ if (str.back() == '\n')
+ str.resize(str.size() - 1);
+ if (str.back() == '\r')
+ str.resize(str.size() - 1);
+
+ list.push_back(std::move(str));
+ return total;
+}
+
+bool GetRemoteFile(
+ const char *url,
+ std::string &str,
+ std::string &error,
+ long *responseCode,
+ const char *contentType,
+ const char *postData,
+ std::vector extraHeaders,
+ std::string *signature)
+{
+ vector header_in_list;
+ char error_in[CURL_ERROR_SIZE];
+ CURLcode code = CURLE_FAILED_INIT;
+
+ error_in[0] = 0;
+
+ string versionString("User-Agent: obs-basic ");
+ versionString += App()->GetVersionString();
+
+ string contentTypeString;
+ if (contentType) {
+ contentTypeString += "Content-Type: ";
+ contentTypeString += contentType;
+ }
+
+ Curl curl{curl_easy_init(), curl_deleter};
+ if (curl) {
+ struct curl_slist *header = nullptr;
+
+ header = curl_slist_append(header,
+ versionString.c_str());
+
+ if (!contentTypeString.empty()) {
+ header = curl_slist_append(header,
+ contentTypeString.c_str());
+ }
+
+ for (std::string &h : extraHeaders)
+ header = curl_slist_append(header, h.c_str());
+
+ curl_easy_setopt(curl.get(), CURLOPT_URL, url);
+ curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER,
+ header);
+ curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER,
+ error_in);
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION,
+ string_write);
+ curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA,
+ &str);
+ if (signature) {
+ curl_easy_setopt(curl.get(), CURLOPT_HEADERFUNCTION,
+ header_write);
+ curl_easy_setopt(curl.get(), CURLOPT_HEADERDATA,
+ &header_in_list);
+ }
+
+#if LIBCURL_VERSION_NUM >= 0x072400
+ // A lot of servers don't yet support ALPN
+ curl_easy_setopt(curl.get(), CURLOPT_SSL_ENABLE_ALPN, 0);
+#endif
+
+ if (postData) {
+ curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS,
+ postData);
+ }
+
+ code = curl_easy_perform(curl.get());
+ if (responseCode)
+ curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE,
+ responseCode);
+
+ if (code != CURLE_OK) {
+ error = error_in;
+ } else if (signature) {
+ for (string &h : header_in_list) {
+ string name = h.substr(0, 13);
+ if (name == "X-Signature: ") {
+ *signature = h.substr(13);
+ break;
+ }
+ }
+ }
+
+ curl_slist_free_all(header);
+ }
+
+ return code == CURLE_OK;
+}
diff --git a/UI/remote-text.hpp b/UI/remote-text.hpp
index e0e2268..7758843 100644
--- a/UI/remote-text.hpp
+++ b/UI/remote-text.hpp
@@ -18,6 +18,7 @@
#pragma once
#include
+#include
#include
class RemoteTextThread : public QThread {
@@ -40,3 +41,13 @@ public:
: url(url_), contentType(contentType_), postData(postData_)
{}
};
+
+bool GetRemoteFile(
+ const char *url,
+ std::string &str,
+ std::string &error,
+ long *responseCode = nullptr,
+ const char *contentType = nullptr,
+ const char *postData = nullptr,
+ std::vector extraHeaders = std::vector(),
+ std::string *signature = nullptr);
diff --git a/UI/volume-control.cpp b/UI/volume-control.cpp
index 02456a4..ba66209 100644
--- a/UI/volume-control.cpp
+++ b/UI/volume-control.cpp
@@ -1,8 +1,10 @@
#include "volume-control.hpp"
#include "qt-wrappers.hpp"
+#include "obs-app.hpp"
#include "mute-checkbox.hpp"
#include "slider-absoluteset-style.hpp"
#include
+#include
#include
#include
#include
@@ -16,6 +18,8 @@
using namespace std;
+QWeakPointer VolumeMeter::updateTimer;
+
void VolControl::OBSVolumeChanged(void *data, float db)
{
Q_UNUSED(db);
@@ -29,11 +33,10 @@ void VolControl::OBSVolumeLevel(void *data, float level, float mag,
{
VolControl *volControl = static_cast(data);
- QMetaObject::invokeMethod(volControl, "VolumeLevel",
- Q_ARG(float, mag),
- Q_ARG(float, level),
- Q_ARG(float, peak),
- Q_ARG(bool, muted));
+ if (muted)
+ level = mag = peak = 0.0f;
+
+ volControl->volMeter->setLevels(mag, level, peak);
}
void VolControl::OBSVolumeMuted(void *data, calldata_t *calldata)
@@ -84,8 +87,19 @@ void VolControl::SliderChanged(int vol)
void VolControl::updateText()
{
- volLabel->setText(QString::number(obs_fader_get_db(obs_fader), 'f', 1)
- .append(" dB"));
+ QString db = QString::number(obs_fader_get_db(obs_fader), 'f', 1)
+ .append(" dB");
+ volLabel->setText(db);
+
+ bool muted = obs_source_muted(source);
+ const char *accTextLookup = muted
+ ? "VolControl.SliderMuted"
+ : "VolControl.SliderUnmuted";
+
+ QString sourceName = obs_source_get_name(source);
+ QString accText = QTStr(accTextLookup).arg(sourceName, db);
+
+ slider->setAccessibleName(accText);
}
QString VolControl::GetName() const
@@ -124,7 +138,9 @@ VolControl::VolControl(OBSSource source_, bool showConfig)
QFont font = nameLabel->font();
font.setPointSize(font.pointSize()-1);
- nameLabel->setText(obs_source_get_name(source));
+ QString sourceName = obs_source_get_name(source);
+
+ nameLabel->setText(sourceName);
nameLabel->setFont(font);
volLabel->setFont(font);
slider->setMinimum(0);
@@ -138,7 +154,10 @@ VolControl::VolControl(OBSSource source_, bool showConfig)
textLayout->setAlignment(nameLabel, Qt::AlignLeft);
textLayout->setAlignment(volLabel, Qt::AlignRight);
- mute->setChecked(obs_source_muted(source));
+ bool muted = obs_source_muted(source);
+ mute->setChecked(muted);
+ mute->setAccessibleName(
+ QTStr("VolControl.Mute").arg(sourceName));
volLayout->addWidget(slider);
volLayout->addWidget(mute);
@@ -157,6 +176,9 @@ VolControl::VolControl(OBSSource source_, bool showConfig)
config->setMaximumSize(22, 22);
config->setAutoDefault(false);
+ config->setAccessibleName(QTStr("VolControl.Properties")
+ .arg(sourceName));
+
connect(config, &QAbstractButton::clicked,
this, &VolControl::EmitConfigClicked);
@@ -255,30 +277,51 @@ VolumeMeter::VolumeMeter(QWidget *parent)
peakColor.setRgb(0x3E, 0xF1, 0x2B);
peakHoldColor.setRgb(0x00, 0x00, 0x00);
- resetTimer = new QTimer(this);
- connect(resetTimer, SIGNAL(timeout()), this, SLOT(resetState()));
+ updateTimerRef = updateTimer.toStrongRef();
+ if (!updateTimerRef) {
+ updateTimerRef = QSharedPointer::create();
+ updateTimerRef->start(34);
+ updateTimer = updateTimerRef;
+ }
- resetState();
+ updateTimerRef->AddVolControl(this);
}
-void VolumeMeter::resetState(void)
+VolumeMeter::~VolumeMeter()
{
- setLevels(0.0f, 0.0f, 0.0f);
- if (resetTimer->isActive())
- resetTimer->stop();
+ updateTimerRef->RemoveVolControl(this);
}
void VolumeMeter::setLevels(float nmag, float npeak, float npeakHold)
{
- mag = nmag;
- peak = npeak;
- peakHold = npeakHold;
+ uint64_t ts = os_gettime_ns();
+ QMutexLocker locker(&dataMutex);
- update();
+ mag += nmag;
+ peak += npeak;
+ peakHold += npeakHold;
+ multiple += 1.0f;
+ lastUpdateTime = ts;
+}
- if (resetTimer->isActive())
- resetTimer->stop();
- resetTimer->start(1000);
+inline void VolumeMeter::calcLevels()
+{
+ uint64_t ts = os_gettime_ns();
+ QMutexLocker locker(&dataMutex);
+
+ if (lastUpdateTime && ts - lastUpdateTime > 1000000000) {
+ mag = peak = peakHold = 0.0f;
+ multiple = 1.0f;
+ lastUpdateTime = 0;
+ }
+
+ if (multiple > 0.0f) {
+ curMag = mag / multiple;
+ curPeak = peak / multiple;
+ curPeakHold = peakHold / multiple;
+
+ mag = peak = peakHold = multiple = 0.0f;
+ }
}
void VolumeMeter::paintEvent(QPaintEvent *event)
@@ -291,9 +334,11 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
int width = size().width();
int height = size().height();
- int scaledMag = int((float)width * mag);
- int scaledPeak = int((float)width * peak);
- int scaledPeakHold = int((float)width * peakHold);
+ calcLevels();
+
+ int scaledMag = int((float)width * curMag);
+ int scaledPeak = int((float)width * curPeak);
+ int scaledPeakHold = int((float)width * curPeakHold);
gradient.setStart(qreal(scaledMag), 0);
gradient.setFinalStop(qreal(scaledPeak), 0);
@@ -324,3 +369,19 @@ void VolumeMeter::paintEvent(QPaintEvent *event)
scaledPeakHold, height);
}
+
+void VolumeMeterTimer::AddVolControl(VolumeMeter *meter)
+{
+ volumeMeters.push_back(meter);
+}
+
+void VolumeMeterTimer::RemoveVolControl(VolumeMeter *meter)
+{
+ volumeMeters.removeOne(meter);
+}
+
+void VolumeMeterTimer::timerEvent(QTimerEvent*)
+{
+ for (VolumeMeter *meter : volumeMeters)
+ meter->update();
+}
diff --git a/UI/volume-control.hpp b/UI/volume-control.hpp
index 27b52b2..9330af7 100644
--- a/UI/volume-control.hpp
+++ b/UI/volume-control.hpp
@@ -2,8 +2,13 @@
#include
#include
+#include
+#include
+#include
+#include
class QPushButton;
+class VolumeMeterTimer;
class VolumeMeter : public QWidget
{
@@ -14,12 +19,23 @@ class VolumeMeter : public QWidget
Q_PROPERTY(QColor peakHoldColor READ getPeakHoldColor WRITE setPeakHoldColor DESIGNABLE true)
private:
- float mag, peak, peakHold;
+ static QWeakPointer updateTimer;
+ QSharedPointer updateTimerRef;
+ float curMag = 0.0f, curPeak = 0.0f, curPeakHold = 0.0f;
+
+ inline void calcLevels();
+
+ QMutex dataMutex;
+ float mag = 0.0f, peak = 0.0f, peakHold = 0.0f;
+ float multiple = 0.0f;
+ uint64_t lastUpdateTime = 0;
+
QColor bkColor, magColor, peakColor, peakHoldColor;
- QTimer *resetTimer;
public:
explicit VolumeMeter(QWidget *parent = 0);
+ ~VolumeMeter();
+
void setLevels(float nmag, float npeak, float npeakHold);
QColor getBkColor() const;
void setBkColor(QColor c);
@@ -32,8 +48,20 @@ public:
protected:
void paintEvent(QPaintEvent *event);
-private slots:
- void resetState();
+};
+
+class VolumeMeterTimer : public QTimer {
+ Q_OBJECT
+
+public:
+ inline VolumeMeterTimer() : QTimer() {}
+
+ void AddVolControl(VolumeMeter *meter);
+ void RemoveVolControl(VolumeMeter *meter);
+
+protected:
+ virtual void timerEvent(QTimerEvent *event) override;
+ QList volumeMeters;
};
class QLabel;
diff --git a/UI/win-update/update-window.cpp b/UI/win-update/update-window.cpp
new file mode 100644
index 0000000..9c2dcf7
--- /dev/null
+++ b/UI/win-update/update-window.cpp
@@ -0,0 +1,44 @@
+#include "update-window.hpp"
+#include "obs-app.hpp"
+
+OBSUpdate::OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text)
+ : QDialog (parent, Qt::WindowSystemMenuHint |
+ Qt::WindowTitleHint |
+ Qt::WindowCloseButtonHint),
+ ui (new Ui_OBSUpdate)
+{
+ ui->setupUi(this);
+ ui->text->setHtml(text);
+
+ if (manualUpdate) {
+ delete ui->skip;
+ ui->skip = nullptr;
+
+ ui->no->setText(QTStr("Cancel"));
+ }
+}
+
+void OBSUpdate::on_yes_clicked()
+{
+ done(OBSUpdate::Yes);
+}
+
+void OBSUpdate::on_no_clicked()
+{
+ done(OBSUpdate::No);
+}
+
+void OBSUpdate::on_skip_clicked()
+{
+ done(OBSUpdate::Skip);
+}
+
+void OBSUpdate::accept()
+{
+ done(OBSUpdate::Yes);
+}
+
+void OBSUpdate::reject()
+{
+ done(OBSUpdate::No);
+}
diff --git a/UI/win-update/update-window.hpp b/UI/win-update/update-window.hpp
new file mode 100644
index 0000000..361e730
--- /dev/null
+++ b/UI/win-update/update-window.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+#include
+
+#include "ui_OBSUpdate.h"
+
+class OBSUpdate : public QDialog {
+ Q_OBJECT
+
+public:
+ enum ReturnVal {
+ No,
+ Yes,
+ Skip
+ };
+
+ OBSUpdate(QWidget *parent, bool manualUpdate, const QString &text);
+
+public slots:
+ void on_yes_clicked();
+ void on_no_clicked();
+ void on_skip_clicked();
+ virtual void accept() override;
+ virtual void reject() override;
+
+private:
+ std::unique_ptr ui;
+};
diff --git a/UI/win-update/updater/CMakeLists.txt b/UI/win-update/updater/CMakeLists.txt
new file mode 100644
index 0000000..e158475
--- /dev/null
+++ b/UI/win-update/updater/CMakeLists.txt
@@ -0,0 +1,51 @@
+if(NOT ENABLE_WIN_UPDATER)
+ return()
+endif()
+
+if(NOT DEFINED STATIC_ZLIB_PATH OR "${STATIC_ZLIB_PATH}" STREQUAL "")
+ message(STATUS "STATIC_ZLIB_PATH not set, windows updater disabled")
+ return()
+endif()
+
+project(updater)
+
+include_directories(${OBS_JANSSON_INCLUDE_DIRS})
+include_directories(${LIBLZMA_INCLUDE_DIRS})
+include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
+include_directories(${BLAKE2_INCLUDE_DIR})
+
+find_package(ZLIB REQUIRED)
+
+set(updater_HEADERS
+ ../win-update-helpers.hpp
+ resource.h
+ updater.hpp
+ )
+set(updater_SOURCES
+ ../win-update-helpers.cpp
+ updater.cpp
+ patch.cpp
+ http.cpp
+ hash.cpp
+ updater.rc
+ )
+
+add_definitions(-DNOMINMAX -DUNICODE -D_UNICODE)
+if(MSVC)
+ add_compile_options("$<$:/MT>")
+endif()
+
+add_executable(updater WIN32
+ ${updater_HEADERS}
+ ${updater_SOURCES}
+ )
+target_link_libraries(updater
+ ${OBS_JANSSON_IMPORT}
+ ${STATIC_ZLIB_PATH}
+ lzma
+ blake2
+ psapi
+ comctl32
+ shell32
+ winhttp
+ )
diff --git a/UI/win-update/updater/hash.cpp b/UI/win-update/updater/hash.cpp
new file mode 100644
index 0000000..69033b0
--- /dev/null
+++ b/UI/win-update/updater/hash.cpp
@@ -0,0 +1,61 @@
+#include "updater.hpp"
+
+#include
+#include
+
+using namespace std;
+
+void HashToString(const uint8_t *in, wchar_t *out)
+{
+ const wchar_t alphabet[] = L"0123456789abcdef";
+
+ for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) {
+ out[2 * i] = alphabet[in[i] / 16];
+ out[2 * i + 1] = alphabet[in[i] % 16];
+ }
+
+ out[BLAKE2_HASH_LENGTH * 2] = 0;
+}
+
+void StringToHash(const wchar_t *in, BYTE *out)
+{
+ int temp;
+
+ for (int i = 0; i < BLAKE2_HASH_LENGTH; i++) {
+ swscanf_s(in + i * 2, L"%02x", &temp);
+ out[i] = (BYTE)temp;
+ }
+}
+
+bool CalculateFileHash(const wchar_t *path, BYTE *hash)
+{
+ blake2b_state blake2;
+ if (blake2b_init(&blake2, BLAKE2_HASH_LENGTH) != 0)
+ return false;
+
+ WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
+ nullptr, OPEN_EXISTING, 0, nullptr);
+ if (handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ vector buf;
+ buf.resize(65536);
+
+ for (;;) {
+ DWORD read = 0;
+ if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read,
+ nullptr))
+ return false;
+
+ if (!read)
+ break;
+
+ if (blake2b_update(&blake2, buf.data(), read) != 0)
+ return false;
+ }
+
+ if (blake2b_final(&blake2, hash, BLAKE2_HASH_LENGTH) != 0)
+ return false;
+
+ return true;
+}
diff --git a/UI/win-update/updater/http.cpp b/UI/win-update/updater/http.cpp
new file mode 100644
index 0000000..cbea2b3
--- /dev/null
+++ b/UI/win-update/updater/http.cpp
@@ -0,0 +1,537 @@
+#include "Updater.hpp"
+
+#include
+
+using namespace std;
+
+#define MAX_BUF_SIZE 262144
+#define READ_BUF_SIZE 32768
+
+/* ------------------------------------------------------------------------ */
+
+class ZipStream {
+ z_stream strm = {};
+ bool initialized = false;
+
+public:
+ inline ~ZipStream()
+ {
+ if (initialized)
+ inflateEnd(&strm);
+ }
+
+ inline operator z_stream*() {return &strm;}
+ inline z_stream *operator->() {return &strm;}
+
+ inline bool inflate()
+ {
+ int ret = inflateInit2(&strm, 16 + MAX_WBITS);
+ initialized = (ret == Z_OK);
+ return initialized;
+ }
+};
+
+/* ------------------------------------------------------------------------ */
+
+static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
+ string &zipBuf, const uint8_t *buffer, DWORD outSize)
+{
+ do {
+ strm->avail_in = outSize;
+ strm->next_in = buffer;
+
+ strm->avail_out = (uInt)zipBuf.size();
+ strm->next_out = (Bytef *)zipBuf.data();
+
+ int zret = inflate(strm, Z_NO_FLUSH);
+ if (zret != Z_STREAM_END && zret != Z_OK)
+ return false;
+
+ try {
+ responseBuf.append(zipBuf.data(),
+ zipBuf.size() - strm->avail_out);
+ } catch (...) {
+ return false;
+ }
+ } while (strm->avail_out == 0);
+
+ return true;
+}
+
+static bool ReadHTTPData(string &responseBuf, const uint8_t *buffer,
+ DWORD outSize)
+{
+ try {
+ responseBuf.append((const char *)buffer, outSize);
+ } catch (...) {
+ return false;
+ }
+ return true;
+}
+
+bool HTTPPostData(const wchar_t *url,
+ const BYTE * data,
+ int dataLen,
+ const wchar_t *extraHeaders,
+ int * responseCode,
+ string & responseBuf)
+{
+ HttpHandle hSession;
+ HttpHandle hConnect;
+ HttpHandle hRequest;
+ string zipBuf;
+ URL_COMPONENTS urlComponents = {};
+ bool secure = false;
+
+ wchar_t hostName[256];
+ wchar_t path[1024];
+
+ const wchar_t *acceptTypes[] = {L"*/*", nullptr};
+
+ responseBuf.clear();
+
+ /* -------------------------------------- *
+ * get URL components */
+
+ urlComponents.dwStructSize = sizeof(urlComponents);
+
+ urlComponents.lpszHostName = hostName;
+ urlComponents.dwHostNameLength = _countof(hostName);
+
+ urlComponents.lpszUrlPath = path;
+ urlComponents.dwUrlPathLength = _countof(path);
+
+ WinHttpCrackUrl(url, 0, 0, &urlComponents);
+
+ if (urlComponents.nPort == 443)
+ secure = true;
+
+ /* -------------------------------------- *
+ * connect to server */
+
+ hSession = WinHttpOpen(L"OBS Updater/2.1",
+ WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0);
+ if (!hSession) {
+ *responseCode = -1;
+ return false;
+ }
+
+ hConnect = WinHttpConnect(hSession, hostName,
+ secure
+ ? INTERNET_DEFAULT_HTTPS_PORT
+ : INTERNET_DEFAULT_HTTP_PORT, 0);
+ if (!hConnect) {
+ *responseCode = -2;
+ return false;
+ }
+
+ /* -------------------------------------- *
+ * request data */
+
+ hRequest = WinHttpOpenRequest(hConnect,
+ L"POST",
+ path,
+ nullptr,
+ WINHTTP_NO_REFERER,
+ acceptTypes,
+ secure
+ ? WINHTTP_FLAG_SECURE |
+ WINHTTP_FLAG_REFRESH
+ : WINHTTP_FLAG_REFRESH);
+ if (!hRequest) {
+ *responseCode = -3;
+ return false;
+ }
+
+ bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
+ extraHeaders ? -1 : 0,
+ (void *)data, dataLen, dataLen, 0);
+
+ /* -------------------------------------- *
+ * end request */
+
+ if (bResults) {
+ bResults = !!WinHttpReceiveResponse(hRequest, nullptr);
+ } else {
+ *responseCode = GetLastError();
+ return false;
+ }
+
+ /* -------------------------------------- *
+ * get headers */
+
+ wchar_t encoding[64];
+ DWORD encodingLen;
+
+ wchar_t statusCode[8];
+ DWORD statusCodeLen;
+
+ statusCodeLen = sizeof(statusCode);
+ if (!WinHttpQueryHeaders(hRequest,
+ WINHTTP_QUERY_STATUS_CODE,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ &statusCode,
+ &statusCodeLen,
+ WINHTTP_NO_HEADER_INDEX)) {
+ *responseCode = -4;
+ return false;
+ } else {
+ statusCode[_countof(statusCode) - 1] = 0;
+ }
+
+ encodingLen = sizeof(encoding);
+ if (!WinHttpQueryHeaders(hRequest,
+ WINHTTP_QUERY_CONTENT_ENCODING,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ encoding,
+ &encodingLen,
+ WINHTTP_NO_HEADER_INDEX)) {
+ encoding[0] = 0;
+ if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
+ *responseCode = -5;
+ return false;
+ }
+ } else {
+ encoding[_countof(encoding) - 1] = 0;
+ }
+
+ /* -------------------------------------- *
+ * allocate response data */
+
+ DWORD responseBufSize = MAX_BUF_SIZE;
+
+ try {
+ responseBuf.reserve(responseBufSize);
+ } catch (...) {
+ *responseCode = -6;
+ return false;
+ }
+
+ /* -------------------------------------- *
+ * if zipped, initialize zip data */
+
+ ZipStream strm;
+ bool gzip = wcscmp(encoding, L"gzip") == 0;
+
+ if (gzip) {
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ strm->avail_in = 0;
+ strm->next_in = Z_NULL;
+
+ if (!strm.inflate())
+ return false;
+
+ try {
+ zipBuf.resize(MAX_BUF_SIZE);
+ } catch (...) {
+ *responseCode = -6;
+ return false;
+ }
+ }
+
+ /* -------------------------------------- *
+ * read data */
+
+ *responseCode = wcstoul(statusCode, nullptr, 10);
+
+ /* are we supposed to return true here? */
+ if (!bResults || *responseCode != 200)
+ return true;
+
+ BYTE buffer[READ_BUF_SIZE];
+ DWORD dwSize, outSize;
+
+ do {
+ /* Check for available data. */
+ dwSize = 0;
+ if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
+ *responseCode = -8;
+ return false;
+ }
+
+ dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
+
+ if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
+ &outSize)) {
+ *responseCode = -9;
+ return false;
+ }
+
+ if (!outSize)
+ break;
+
+ if (gzip) {
+ if (!ReadZippedHTTPData(responseBuf, strm, zipBuf,
+ buffer, outSize)) {
+ *responseCode = -6;
+ return false;
+ }
+ } else {
+ if (!ReadHTTPData(responseBuf, buffer, outSize)) {
+ *responseCode = -6;
+ return false;
+ }
+ }
+
+ if (WaitForSingleObject(cancelRequested, 0) == WAIT_OBJECT_0) {
+ *responseCode = -14;
+ return false;
+ }
+ } while (dwSize > 0);
+
+ return true;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static bool ReadHTTPZippedFile(z_stream *strm, HANDLE updateFile,
+ string &zipBuf, const uint8_t *buffer, DWORD outSize,
+ int *responseCode)
+{
+ do {
+ strm->avail_in = outSize;
+ strm->next_in = buffer;
+
+ strm->avail_out = (uInt)zipBuf.size();
+ strm->next_out = (Bytef *)zipBuf.data();
+
+ int zret = inflate(strm, Z_NO_FLUSH);
+ if (zret != Z_STREAM_END && zret != Z_OK)
+ return false;
+
+ DWORD written;
+ if (!WriteFile(updateFile,
+ zipBuf.data(),
+ MAX_BUF_SIZE - strm->avail_out,
+ &written,
+ nullptr)) {
+ *responseCode = -10;
+ return false;
+ }
+ if (written != MAX_BUF_SIZE - strm->avail_out) {
+ *responseCode = -11;
+ return false;
+ }
+
+ completedFileSize += written;
+ } while (strm->avail_out == 0);
+
+ return true;
+}
+
+static bool ReadHTTPFile(HANDLE updateFile, const uint8_t *buffer,
+ DWORD outSize, int *responseCode)
+{
+ DWORD written;
+ if (!WriteFile(updateFile, buffer, outSize, &written, nullptr)) {
+ *responseCode = -12;
+ return false;
+ }
+
+ if (written != outSize) {
+ *responseCode = -13;
+ return false;
+ }
+
+ completedFileSize += outSize;
+ return true;
+}
+
+bool HTTPGetFile(HINTERNET hConnect,
+ const wchar_t *url,
+ const wchar_t *outputPath,
+ const wchar_t *extraHeaders,
+ int * responseCode)
+{
+ HttpHandle hRequest;
+
+ const wchar_t *acceptTypes[] = {L"*/*", nullptr};
+
+ URL_COMPONENTS urlComponents = {};
+ bool secure = false;
+
+ string zipBuf;
+ wchar_t hostName[256];
+ wchar_t path[1024];
+
+ /* -------------------------------------- *
+ * get URL components */
+
+ urlComponents.dwStructSize = sizeof(urlComponents);
+
+ urlComponents.lpszHostName = hostName;
+ urlComponents.dwHostNameLength = _countof(hostName);
+
+ urlComponents.lpszUrlPath = path;
+ urlComponents.dwUrlPathLength = _countof(path);
+
+ WinHttpCrackUrl(url, 0, 0, &urlComponents);
+
+ if (urlComponents.nPort == 443)
+ secure = true;
+
+ /* -------------------------------------- *
+ * request data */
+
+ hRequest = WinHttpOpenRequest(hConnect,
+ L"GET",
+ path,
+ nullptr,
+ WINHTTP_NO_REFERER,
+ acceptTypes,
+ secure
+ ? WINHTTP_FLAG_SECURE |
+ WINHTTP_FLAG_REFRESH
+ : WINHTTP_FLAG_REFRESH);
+ if (!hRequest) {
+ *responseCode = -3;
+ return false;
+ }
+
+ bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
+ extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
+
+ /* -------------------------------------- *
+ * end request */
+
+ if (bResults) {
+ bResults = !!WinHttpReceiveResponse(hRequest, nullptr);
+ } else {
+ *responseCode = GetLastError();
+ return false;
+ }
+
+ /* -------------------------------------- *
+ * get headers */
+
+ wchar_t encoding[64];
+ DWORD encodingLen;
+
+ wchar_t statusCode[8];
+ DWORD statusCodeLen;
+
+ statusCodeLen = sizeof(statusCode);
+ if (!WinHttpQueryHeaders(hRequest,
+ WINHTTP_QUERY_STATUS_CODE,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ &statusCode,
+ &statusCodeLen,
+ WINHTTP_NO_HEADER_INDEX)) {
+ *responseCode = -4;
+ return false;
+ } else {
+ statusCode[_countof(statusCode) - 1] = 0;
+ }
+
+ encodingLen = sizeof(encoding);
+ if (!WinHttpQueryHeaders(hRequest,
+ WINHTTP_QUERY_CONTENT_ENCODING,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ encoding,
+ &encodingLen,
+ WINHTTP_NO_HEADER_INDEX)) {
+ encoding[0] = 0;
+ if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
+ *responseCode = -5;
+ return false;
+ }
+ } else {
+ encoding[_countof(encoding) - 1] = 0;
+ }
+
+ /* -------------------------------------- *
+ * allocate response data */
+
+ ZipStream strm;
+ bool gzip = wcscmp(encoding, L"gzip") == 0;
+
+ if (gzip) {
+ strm->zalloc = Z_NULL;
+ strm->zfree = Z_NULL;
+ strm->opaque = Z_NULL;
+ strm->avail_in = 0;
+ strm->next_in = Z_NULL;
+
+ if (!strm.inflate())
+ return false;
+
+ try {
+ zipBuf.resize(MAX_BUF_SIZE);
+ } catch (...) {
+ *responseCode = -6;
+ return false;
+ }
+ }
+
+ /* -------------------------------------- *
+ * read data */
+
+ *responseCode = wcstoul(statusCode, nullptr, 10);
+
+ /* are we supposed to return true here? */
+ if (!bResults || *responseCode != 200)
+ return true;
+
+ BYTE buffer[READ_BUF_SIZE];
+ DWORD dwSize, outSize;
+ int lastPosition = 0;
+
+ WinHandle updateFile = CreateFile(outputPath, GENERIC_WRITE, 0,
+ nullptr, CREATE_ALWAYS, 0, nullptr);
+ if (!updateFile.Valid()) {
+ *responseCode = -7;
+ return false;
+ }
+
+ do {
+ /* Check for available data. */
+ dwSize = 0;
+ if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
+ *responseCode = -8;
+ return false;
+ }
+
+ dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
+
+ if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
+ &outSize)) {
+ *responseCode = -9;
+ return false;
+ } else {
+ if (!outSize)
+ break;
+
+ if (gzip) {
+ if (!ReadHTTPZippedFile(strm, updateFile,
+ zipBuf, buffer,
+ outSize, responseCode))
+ return false;
+ } else {
+ if (!ReadHTTPFile(updateFile, buffer,
+ outSize, responseCode))
+ return false;
+ }
+
+ int position = (int)(((float)completedFileSize /
+ (float)totalFileSize) * 100.0f);
+ if (position > lastPosition) {
+ lastPosition = position;
+ SendDlgItemMessage(hwndMain, IDC_PROGRESS,
+ PBM_SETPOS, position, 0);
+ }
+ }
+
+ if (WaitForSingleObject(cancelRequested, 0) == WAIT_OBJECT_0) {
+ *responseCode = -14;
+ return false;
+ }
+
+ } while (dwSize > 0);
+
+ return true;
+}
diff --git a/UI/win-update/updater/patch.cpp b/UI/win-update/updater/patch.cpp
new file mode 100644
index 0000000..a801168
--- /dev/null
+++ b/UI/win-update/updater/patch.cpp
@@ -0,0 +1,301 @@
+#include "updater.hpp"
+
+#include
+#include
+
+#include
+
+using namespace std;
+
+#define MAX_BUF_SIZE 262144
+#define READ_BUF_SIZE 32768
+
+/* ------------------------------------------------------------------------ */
+
+class LZMAStream {
+ lzma_stream strm = {};
+ bool initialized = false;
+
+public:
+ inline ~LZMAStream()
+ {
+ if (initialized) {
+ lzma_end(&strm);
+ }
+ }
+
+ inline bool init_decoder()
+ {
+ lzma_ret ret = lzma_stream_decoder(
+ &strm,
+ 200 * 1024 * 1024,
+ 0);
+ initialized = (ret == LZMA_OK);
+ return initialized;
+ }
+
+ inline operator lzma_stream *() { return &strm; }
+ inline bool operator!() const { return !initialized; }
+
+ inline lzma_stream *get() { return &strm; }
+};
+
+class File {
+ FILE *f = nullptr;
+
+public:
+ inline ~File()
+ {
+ if (f)
+ fclose(f);
+ }
+
+ inline FILE **operator&() { return &f; }
+ inline operator FILE *() const { return f; }
+ inline bool operator!() const { return !f; }
+};
+
+/* ------------------------------------------------------------------------ */
+
+struct bspatch_stream {
+ void *opaque;
+ int (*read)(const struct bspatch_stream *stream, void *buffer,
+ int length);
+};
+
+/* ------------------------------------------------------------------------ */
+
+static int64_t offtin(const uint8_t *buf)
+{
+ int64_t y;
+
+ y = buf[7] & 0x7F;
+ y = y * 256;
+ y += buf[6];
+ y = y * 256;
+ y += buf[5];
+ y = y * 256;
+ y += buf[4];
+ y = y * 256;
+ y += buf[3];
+ y = y * 256;
+ y += buf[2];
+ y = y * 256;
+ y += buf[1];
+ y = y * 256;
+ y += buf[0];
+
+ if (buf[7] & 0x80)
+ y = -y;
+
+ return y;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int bspatch(const uint8_t *old, int64_t oldsize, uint8_t *newp,
+ int64_t newsize, struct bspatch_stream *stream)
+{
+ uint8_t buf[8];
+ int64_t oldpos, newpos;
+ int64_t ctrl[3];
+ int64_t i;
+
+ oldpos = 0;
+ newpos = 0;
+ while (newpos < newsize) {
+ /* Read control data */
+ for (i = 0; i <= 2; i++) {
+ if (stream->read(stream, buf, 8))
+ return -1;
+ ctrl[i] = offtin(buf);
+ };
+
+ /* Sanity-check */
+ if (newpos + ctrl[0] > newsize)
+ return -1;
+
+ /* Read diff string */
+ if (stream->read(stream, newp + newpos, (int)ctrl[0]))
+ return -1;
+
+ /* Add old data to diff string */
+ for (i = 0; i < ctrl[0]; i++)
+ if ((oldpos + i >= 0) && (oldpos + i < oldsize))
+ newp[newpos + i] += old[oldpos + i];
+
+ /* Adjust pointers */
+ newpos += ctrl[0];
+ oldpos += ctrl[0];
+
+ /* Sanity-check */
+ if (newpos + ctrl[1] > newsize)
+ return -1;
+
+ /* Read extra string */
+ if (stream->read(stream, newp + newpos, (int)ctrl[1]))
+ return -1;
+
+ /* Adjust pointers */
+ newpos += ctrl[1];
+ oldpos += ctrl[2];
+ };
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+struct patch_data {
+ HANDLE h;
+ lzma_stream *strm;
+ uint8_t buf[READ_BUF_SIZE];
+};
+
+static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
+{
+ if (!len)
+ return 0;
+
+ patch_data *data = (patch_data*)stream->opaque;
+ HANDLE h = data->h;
+ lzma_stream *strm = data->strm;
+
+ strm->avail_out = (size_t)len;
+ strm->next_out = (uint8_t *)buffer;
+
+ for (;;) {
+ if (strm->avail_in == 0) {
+ DWORD read_size;
+ if (!ReadFile(h, data->buf, READ_BUF_SIZE, &read_size,
+ nullptr))
+ return -1;
+ if (read_size == 0)
+ return -1;
+
+ strm->avail_in = (size_t)read_size;
+ strm->next_in = data->buf;
+ }
+
+ lzma_ret ret = lzma_code(strm, LZMA_RUN);
+ if (ret == LZMA_STREAM_END)
+ return 0;
+ if (ret != LZMA_OK)
+ return -1;
+ if (strm->avail_out == 0)
+ break;
+ }
+
+ return 0;
+}
+
+int ApplyPatch(const wchar_t *patchFile, const wchar_t *targetFile)
+try {
+ uint8_t header[24];
+ int64_t newsize;
+ struct bspatch_stream stream;
+ bool success;
+
+ WinHandle hPatch;
+ WinHandle hTarget;
+ LZMAStream strm;
+
+ /* --------------------------------- *
+ * open patch and file to patch */
+
+ hPatch = CreateFile(patchFile, GENERIC_READ, 0, nullptr,
+ OPEN_EXISTING, 0, nullptr);
+ if (!hPatch.Valid())
+ throw int(GetLastError());
+
+ hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr,
+ OPEN_EXISTING, 0, nullptr);
+ if (!hTarget.Valid())
+ throw int(GetLastError());
+
+ /* --------------------------------- *
+ * read patch header */
+
+ DWORD read;
+ success = !!ReadFile(hPatch, header, sizeof(header), &read, nullptr);
+ if (success && read == sizeof(header)) {
+ if (memcmp(header, "JIMSLEY/BSDIFF43", 16))
+ throw int(-4);
+ } else {
+ throw int(GetLastError());
+ }
+
+ /* --------------------------------- *
+ * allocate new file size data */
+
+ newsize = offtin(header + 16);
+ if (newsize < 0 || newsize >= 0x7ffffffff)
+ throw int(-5);
+
+ vector newData;
+ try {
+ newData.resize(newsize);
+ } catch (...) {
+ throw int(-1);
+ }
+
+ /* --------------------------------- *
+ * read old file */
+
+ DWORD targetFileSize;
+
+ targetFileSize = GetFileSize(hTarget, nullptr);
+ if (targetFileSize == INVALID_FILE_SIZE)
+ throw int(GetLastError());
+
+ vector oldData;
+ try {
+ oldData.resize(targetFileSize);
+ } catch (...) {
+ throw int(-1);
+ }
+
+ if (!ReadFile(hTarget, &oldData[0], targetFileSize, &read, nullptr))
+ throw int(GetLastError());
+ if (read != targetFileSize)
+ throw int(-1);
+
+ /* --------------------------------- *
+ * patch to new file data */
+
+ if (!strm.init_decoder())
+ throw int(-10);
+
+ patch_data data;
+ data.h = hPatch;
+ data.strm = strm.get();
+
+ stream.read = read_lzma;
+ stream.opaque = &data;
+
+ int ret = bspatch(oldData.data(), oldData.size(), newData.data(),
+ newData.size(), &stream);
+ if (ret != 0)
+ throw int(-9);
+
+ /* --------------------------------- *
+ * write new file */
+
+ hTarget = nullptr;
+ hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr,
+ CREATE_ALWAYS, 0, nullptr);
+ if (!hTarget.Valid())
+ throw int(GetLastError());
+
+ DWORD written;
+
+ success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize,
+ &written, nullptr);
+ if (!success || written != newsize)
+ throw int(GetLastError());
+
+ return 0;
+
+} catch (int code) {
+ return code;
+}
diff --git a/UI/win-update/updater/resource.h b/UI/win-update/updater/resource.h
new file mode 100644
index 0000000..9b34eb0
--- /dev/null
+++ b/UI/win-update/updater/resource.h
@@ -0,0 +1,21 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by updater.rc
+//
+#define IDD_UPDATEDIALOG 101
+#define IDI_ICON1 103
+#define IDC_PROGRESS 1001
+#define IDC_STATUS 1002
+#define IDCBUTTON 1004
+#define IDC_BUTTON 1004
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 104
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1005
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/UI/win-update/updater/updater.cpp b/UI/win-update/updater/updater.cpp
new file mode 100644
index 0000000..5ada461
--- /dev/null
+++ b/UI/win-update/updater/updater.cpp
@@ -0,0 +1,1438 @@
+/******************************************************************************
+ Copyright (C) 2017 Hugh Bailey
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+******************************************************************************/
+
+#include "updater.hpp"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+/* ----------------------------------------------------------------------- */
+
+HANDLE cancelRequested = nullptr;
+HANDLE updateThread = nullptr;
+HINSTANCE hinstMain = nullptr;
+HWND hwndMain = nullptr;
+HCRYPTPROV hProvider = 0;
+
+static bool bExiting = false;
+static bool updateFailed = false;
+static bool is32bit = false;
+
+static bool downloadThreadFailure = false;
+
+int totalFileSize = 0;
+int completedFileSize = 0;
+static int completedUpdates = 0;
+
+struct LastError {
+ DWORD code;
+ inline LastError() { code = GetLastError(); }
+};
+
+void FreeWinHttpHandle(HINTERNET handle)
+{
+ WinHttpCloseHandle(handle);
+}
+
+/* ----------------------------------------------------------------------- */
+
+// http://www.codeproject.com/Articles/320748/Haephrati-Elevating-during-runtime
+static bool IsAppRunningAsAdminMode()
+{
+ BOOL fIsRunAsAdmin = FALSE;
+ DWORD dwError = ERROR_SUCCESS;
+ PSID pAdministratorsGroup = nullptr;
+
+ /* Allocate and initialize a SID of the administrators group. */
+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
+ if (!AllocateAndInitializeSid(&NtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &pAdministratorsGroup)) {
+ dwError = GetLastError();
+ goto Cleanup;
+ }
+
+ /* Determine whether the SID of administrators group is enabled in the
+ * primary access token of the process. */
+ if (!CheckTokenMembership(nullptr, pAdministratorsGroup,
+ &fIsRunAsAdmin)) {
+ dwError = GetLastError();
+ goto Cleanup;
+ }
+
+Cleanup:
+ /* Centralized cleanup for all allocated resources. */
+ if (pAdministratorsGroup) {
+ FreeSid(pAdministratorsGroup);
+ pAdministratorsGroup = nullptr;
+ }
+
+ /* Throw the error if something failed in the function. */
+ if (ERROR_SUCCESS != dwError)
+ return false;
+
+ return !!fIsRunAsAdmin;
+}
+
+static void Status(const wchar_t *fmt, ...)
+{
+ wchar_t str[512];
+
+ va_list argptr;
+ va_start(argptr, fmt);
+
+ StringCbVPrintf(str, sizeof(str), fmt, argptr);
+
+ SetDlgItemText(hwndMain, IDC_STATUS, str);
+
+ va_end(argptr);
+}
+
+static void CreateFoldersForPath(const wchar_t *path)
+{
+ wchar_t *p = (wchar_t *)path;
+
+ while (*p) {
+ if (*p == '\\' || *p == '/') {
+ *p = 0;
+ CreateDirectory(path, nullptr);
+ *p = '\\';
+ }
+ p++;
+ }
+}
+
+static bool MyCopyFile(const wchar_t *src, const wchar_t *dest)
+try {
+ WinHandle hSrc;
+ WinHandle hDest;
+
+ hSrc = CreateFile(src, GENERIC_READ, 0, nullptr, OPEN_EXISTING,
+ FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
+ if (!hSrc.Valid())
+ throw LastError();
+
+ hDest = CreateFile(dest, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
+ 0, nullptr);
+ if (!hDest.Valid())
+ throw LastError();
+
+ BYTE buf[65536];
+ DWORD read, wrote;
+
+ for (;;) {
+ if (!ReadFile(hSrc, buf, sizeof(buf), &read, nullptr))
+ throw LastError();
+
+ if (read == 0)
+ break;
+
+ if (!WriteFile(hDest, buf, read, &wrote, nullptr))
+ throw LastError();
+
+ if (wrote != read)
+ return false;
+ }
+
+ return true;
+
+} catch (LastError error) {
+ SetLastError(error.code);
+ return false;
+}
+
+static bool IsSafeFilename(const wchar_t *path)
+{
+ const wchar_t *p = path;
+
+ if (!*p)
+ return false;
+
+ if (wcsstr(path, L".."))
+ return false;
+
+ if (*p == '/')
+ return false;
+
+ while (*p) {
+ if (!isalnum(*p) &&
+ *p != '.' &&
+ *p != '/' &&
+ *p != '_' &&
+ *p != '-')
+ return false;
+ p++;
+ }
+
+ return true;
+}
+
+static string QuickReadFile(const wchar_t *path)
+{
+ string data;
+
+ WinHandle handle = CreateFileW(path, GENERIC_READ, 0, nullptr,
+ OPEN_EXISTING, 0, nullptr);
+ if (!handle.Valid()) {
+ return string();
+ }
+
+ LARGE_INTEGER size;
+
+ if (!GetFileSizeEx(handle, &size)) {
+ return string();
+ }
+
+ data.resize((size_t)size.QuadPart);
+
+ DWORD read;
+ if (!ReadFile(handle,
+ &data[0],
+ (DWORD)data.size(),
+ &read,
+ nullptr)) {
+ return string();
+ }
+ if (read != size.QuadPart) {
+ return string();
+ }
+
+ return data;
+}
+
+/* ----------------------------------------------------------------------- */
+
+enum state_t {
+ STATE_INVALID,
+ STATE_PENDING_DOWNLOAD,
+ STATE_DOWNLOADING,
+ STATE_DOWNLOADED,
+ STATE_INSTALLED,
+};
+
+struct update_t {
+ wstring sourceURL;
+ wstring outputPath;
+ wstring tempPath;
+ wstring previousFile;
+ wstring basename;
+ string packageName;
+
+ DWORD fileSize = 0;
+ BYTE hash[BLAKE2_HASH_LENGTH];
+ BYTE downloadhash[BLAKE2_HASH_LENGTH];
+ BYTE my_hash[BLAKE2_HASH_LENGTH];
+ state_t state = STATE_INVALID;
+ bool has_hash = false;
+ bool patchable = false;
+
+ inline update_t() {}
+ inline update_t(const update_t &from)
+ : sourceURL(from.sourceURL),
+ outputPath(from.outputPath),
+ tempPath(from.tempPath),
+ previousFile(from.previousFile),
+ basename(from.basename),
+ packageName(from.packageName),
+ fileSize(from.fileSize),
+ state(from.state),
+ has_hash(from.has_hash),
+ patchable(from.patchable)
+ {
+ memcpy(hash, from.hash, sizeof(hash));
+ memcpy(downloadhash, from.downloadhash, sizeof(downloadhash));
+ memcpy(my_hash, from.my_hash, sizeof(my_hash));
+ }
+
+ inline update_t(update_t &&from)
+ : sourceURL(std::move(from.sourceURL)),
+ outputPath(std::move(from.outputPath)),
+ tempPath(std::move(from.tempPath)),
+ previousFile(std::move(from.previousFile)),
+ basename(std::move(from.basename)),
+ packageName(std::move(from.packageName)),
+ fileSize(from.fileSize),
+ state(from.state),
+ has_hash(from.has_hash),
+ patchable(from.patchable)
+ {
+ from.state = STATE_INVALID;
+
+ memcpy(hash, from.hash, sizeof(hash));
+ memcpy(downloadhash, from.downloadhash, sizeof(downloadhash));
+ memcpy(my_hash, from.my_hash, sizeof(my_hash));
+ }
+
+ void CleanPartialUpdate()
+ {
+ if (state == STATE_INSTALLED) {
+ if (!previousFile.empty()) {
+ DeleteFile(outputPath.c_str());
+ MyCopyFile(previousFile.c_str(),
+ outputPath.c_str());
+ DeleteFile(previousFile.c_str());
+ } else {
+ DeleteFile(outputPath.c_str());
+ }
+ } else if (state == STATE_DOWNLOADED) {
+ DeleteFile(tempPath.c_str());
+ }
+ }
+
+ inline update_t &operator=(const update_t &from)
+ {
+ sourceURL = from.sourceURL;
+ outputPath = from.outputPath;
+ tempPath = from.tempPath;
+ previousFile = from.previousFile;
+ basename = from.basename;
+ packageName = from.packageName;
+ fileSize = from.fileSize;
+ state = from.state;
+ has_hash = from.has_hash;
+ patchable = from.patchable;
+
+ memcpy(hash, from.hash, sizeof(hash));
+ memcpy(downloadhash, from.downloadhash, sizeof(downloadhash));
+ memcpy(my_hash, from.my_hash, sizeof(my_hash));
+ }
+};
+
+static vector updates;
+static mutex updateMutex;
+
+static inline void CleanupPartialUpdates()
+{
+ for (update_t &update : updates)
+ update.CleanPartialUpdate();
+}
+
+/* ----------------------------------------------------------------------- */
+
+bool DownloadWorkerThread()
+{
+ HttpHandle hSession = WinHttpOpen(L"OBS Studio Updater/2.1",
+ WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0);
+ if (!hSession) {
+ downloadThreadFailure = true;
+ Status(L"Update failed: Couldn't open obsproject.com");
+ return false;
+ }
+
+ HttpHandle hConnect = WinHttpConnect(hSession, L"obsproject.com",
+ INTERNET_DEFAULT_HTTPS_PORT, 0);
+ if (!hConnect) {
+ downloadThreadFailure = true;
+ Status(L"Update failed: Couldn't connect to obsproject.com");
+ return false;
+ }
+
+ for (;;) {
+ bool foundWork = false;
+
+ unique_lock ulock(updateMutex);
+
+ for (update_t &update : updates) {
+ int responseCode;
+
+ DWORD waitResult =
+ WaitForSingleObject(cancelRequested, 0);
+ if (waitResult == WAIT_OBJECT_0) {
+ return false;
+ }
+
+ if (update.state != STATE_PENDING_DOWNLOAD)
+ continue;
+
+ update.state = STATE_DOWNLOADING;
+
+ ulock.unlock();
+
+ foundWork = true;
+
+ if (downloadThreadFailure) {
+ return false;
+ }
+
+ Status(L"Downloading %s", update.outputPath.c_str());
+
+ if (!HTTPGetFile(hConnect,
+ update.sourceURL.c_str(),
+ update.tempPath.c_str(),
+ L"Accept-Encoding: gzip",
+ &responseCode)) {
+
+ downloadThreadFailure = true;
+ DeleteFile(update.tempPath.c_str());
+ Status(L"Update failed: Could not download "
+ L"%s (error code %d)",
+ update.outputPath.c_str(),
+ responseCode);
+ return 1;
+ }
+
+ if (responseCode != 200) {
+ downloadThreadFailure = true;
+ DeleteFile(update.tempPath.c_str());
+ Status(L"Update failed: Could not download "
+ L"%s (error code %d)",
+ update.outputPath.c_str(),
+ responseCode);
+ return 1;
+ }
+
+ BYTE downloadHash[BLAKE2_HASH_LENGTH];
+ if (!CalculateFileHash(update.tempPath.c_str(),
+ downloadHash)) {
+ downloadThreadFailure = true;
+ DeleteFile(update.tempPath.c_str());
+ Status(L"Update failed: Couldn't verify "
+ L"integrity of %s",
+ update.outputPath.c_str());
+ return 1;
+ }
+
+ if (memcmp(update.downloadhash, downloadHash, 20)) {
+ downloadThreadFailure = true;
+ DeleteFile(update.tempPath.c_str());
+ Status(L"Update failed: Integrity check "
+ L"failed on %s",
+ update.outputPath.c_str());
+ return 1;
+ }
+
+ ulock.lock();
+
+ update.state = STATE_DOWNLOADED;
+ completedUpdates++;
+ }
+
+ if (!foundWork) {
+ break;
+ }
+ if (downloadThreadFailure) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool RunDownloadWorkers(int num)
+try {
+ vector> thread_success_results;
+ thread_success_results.resize(num);
+
+ for (future &result : thread_success_results) {
+ result = async(DownloadWorkerThread);
+ }
+ for (future &result : thread_success_results) {
+ if (!result.get()) {
+ return false;
+ }
+ }
+
+ return true;
+
+} catch (...) {
+ return false;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#define WAITIFOBS_SUCCESS 0
+#define WAITIFOBS_WRONG_PROCESS 1
+#define WAITIFOBS_CANCELLED 2
+
+static inline DWORD WaitIfOBS(DWORD id, const wchar_t *expected)
+{
+ wchar_t path[MAX_PATH];
+ wchar_t *name;
+ *path = 0;
+
+ WinHandle proc = OpenProcess(
+ PROCESS_QUERY_INFORMATION |
+ PROCESS_VM_READ |
+ SYNCHRONIZE,
+ false, id);
+ if (!proc.Valid())
+ return WAITIFOBS_WRONG_PROCESS;
+
+ if (!GetProcessImageFileName(proc, path, _countof(path)))
+ return WAITIFOBS_WRONG_PROCESS;
+
+ name = wcsrchr(path, L'\\');
+ if (name)
+ name += 1;
+ else
+ name = path;
+
+ if (_wcsnicmp(name, expected, 5) == 0) {
+ HANDLE hWait[2];
+ hWait[0] = proc;
+ hWait[1] = cancelRequested;
+
+ int i = WaitForMultipleObjects(2, hWait, false, INFINITE);
+ if (i == WAIT_OBJECT_0 + 1)
+ return WAITIFOBS_CANCELLED;
+
+ return WAITIFOBS_SUCCESS;
+ }
+
+ return WAITIFOBS_WRONG_PROCESS;
+}
+
+static bool WaitForOBS()
+{
+ DWORD proc_ids[1024], needed, count;
+ const wchar_t *name = is32bit ? L"obs32" : L"obs64";
+
+ if (!EnumProcesses(proc_ids, sizeof(proc_ids), &needed)) {
+ return true;
+ }
+
+ count = needed / sizeof(DWORD);
+
+ for (DWORD i = 0; i < count; i++) {
+ DWORD id = proc_ids[i];
+ if (id != 0) {
+ switch (WaitIfOBS(id, name)) {
+ case WAITIFOBS_SUCCESS:
+ return true;
+ case WAITIFOBS_WRONG_PROCESS:
+ break;
+ case WAITIFOBS_CANCELLED:
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static inline bool UTF8ToWide(wchar_t *wide, int wideSize, const char *utf8)
+{
+ return !!MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wide, wideSize);
+}
+
+static inline bool WideToUTF8(char *utf8, int utf8Size, const wchar_t *wide)
+{
+ return !!WideCharToMultiByte(CP_UTF8, 0, wide, -1, utf8, utf8Size,
+ nullptr, nullptr);
+}
+
+static inline bool FileExists(const wchar_t *path)
+{
+ WIN32_FIND_DATAW wfd;
+ HANDLE hFind;
+
+ hFind = FindFirstFileW(path, &wfd);
+ if (hFind != INVALID_HANDLE_VALUE)
+ FindClose(hFind);
+
+ return hFind != INVALID_HANDLE_VALUE;
+}
+
+static bool NonCorePackageInstalled(const char *name)
+{
+ if (strcmp(name, "obs-browser") == 0) {
+ return FileExists(L"obs-plugins\\32bit\\obs-browser.dll");
+ } else if (strcmp(name, "realsense") == 0) {
+ return FileExists(L"obs-plugins\\32bit\\win-ivcam.dll");
+ }
+
+ return false;
+}
+
+#define UTF8ToWideBuf(wide, utf8) UTF8ToWide(wide, _countof(wide), utf8)
+#define WideToUTF8Buf(utf8, wide) WideToUTF8(utf8, _countof(utf8), wide)
+
+#define UPDATE_URL L"https://obsproject.com/update_studio"
+
+static bool AddPackageUpdateFiles(json_t *root, size_t idx,
+ const wchar_t *tempPath)
+{
+ json_t *package = json_array_get(root, idx);
+ json_t *name = json_object_get(package, "name");
+ json_t *files = json_object_get(package, "files");
+
+ if (!json_is_array(files))
+ return true;
+ if (!json_is_string(name))
+ return true;
+
+ wchar_t wPackageName[512];
+ const char *packageName = json_string_value(name);
+ size_t fileCount = json_array_size(files);
+
+ if (!UTF8ToWideBuf(wPackageName, packageName))
+ return false;
+
+ if (strcmp(packageName, "core") != 0 &&
+ !NonCorePackageInstalled(packageName))
+ return true;
+
+ for (size_t j = 0; j < fileCount; j++) {
+ json_t *file = json_array_get(files, j);
+ json_t *fileName = json_object_get(file, "name");
+ json_t *hash = json_object_get(file, "hash");
+ json_t *size = json_object_get(file, "size");
+
+ if (!json_is_string(fileName))
+ continue;
+ if (!json_is_string(hash))
+ continue;
+ if (!json_is_integer(size))
+ continue;
+
+ const char *fileUTF8 = json_string_value(fileName);
+ const char *hashUTF8 = json_string_value(hash);
+ int fileSize = (int)json_integer_value(size);
+
+ if (strlen(hashUTF8) != BLAKE2_HASH_LENGTH * 2)
+ continue;
+
+ /* convert strings to wide */
+
+ wchar_t sourceURL[1024];
+ wchar_t updateFileName[MAX_PATH];
+ wchar_t updateHashStr[BLAKE2_HASH_STR_LENGTH];
+ wchar_t tempFilePath[MAX_PATH];
+
+ if (!UTF8ToWideBuf(updateFileName, fileUTF8))
+ continue;
+ if (!UTF8ToWideBuf(updateHashStr, hashUTF8))
+ continue;
+
+ /* make sure paths are safe */
+
+ if (!IsSafeFilename(updateFileName)) {
+ Status(L"Update failed: Unsafe path '%s' found in "
+ L"manifest", updateFileName);
+ return false;
+ }
+
+ StringCbPrintf(sourceURL, sizeof(sourceURL), L"%s/%s/%s",
+ UPDATE_URL, wPackageName, updateFileName);
+ StringCbPrintf(tempFilePath, sizeof(tempFilePath),
+ L"%s\\%s", tempPath, updateHashStr);
+
+ /* Check file hash */
+
+ BYTE existingHash[BLAKE2_HASH_LENGTH];
+ wchar_t fileHashStr[BLAKE2_HASH_STR_LENGTH];
+ bool has_hash;
+
+ /* We don't really care if this fails, it's just to avoid
+ * wasting bandwidth by downloading unmodified files */
+ if (CalculateFileHash(updateFileName, existingHash)) {
+
+ HashToString(existingHash, fileHashStr);
+ if (wcscmp(fileHashStr, updateHashStr) == 0)
+ continue;
+
+ has_hash = true;
+ } else {
+ has_hash = false;
+ }
+
+ /* Add update file */
+
+ update_t update;
+ update.fileSize = fileSize;
+ update.basename = updateFileName;
+ update.outputPath = updateFileName;
+ update.tempPath = tempFilePath;
+ update.sourceURL = sourceURL;
+ update.packageName = packageName;
+ update.state = STATE_PENDING_DOWNLOAD;
+ update.patchable = false;
+
+ StringToHash(updateHashStr, update.downloadhash);
+ memcpy(update.hash, update.downloadhash, sizeof(update.hash));
+
+ update.has_hash = has_hash;
+ if (has_hash)
+ StringToHash(fileHashStr, update.my_hash);
+
+ updates.push_back(move(update));
+
+ totalFileSize += fileSize;
+ }
+
+ return true;
+}
+
+static void UpdateWithPatchIfAvailable(const char *name, const char *hash,
+ const char *source,
+ int size)
+{
+ wchar_t widePatchableFilename[MAX_PATH];
+ wchar_t widePatchHash[MAX_PATH];
+ wchar_t sourceURL[1024];
+ wchar_t patchHashStr[BLAKE2_HASH_STR_LENGTH];
+
+ if (strncmp(source, "https://obsproject.com/", 23) != 0)
+ return;
+
+ string patchPackageName = name;
+
+ const char *slash = strchr(name, '/');
+ if (!slash)
+ return;
+
+ patchPackageName.resize(slash - name);
+ name = slash + 1;
+
+ if (!UTF8ToWideBuf(widePatchableFilename, name))
+ return;
+ if (!UTF8ToWideBuf(widePatchHash, hash))
+ return;
+ if (!UTF8ToWideBuf(sourceURL, source))
+ return;
+ if (!UTF8ToWideBuf(patchHashStr, hash))
+ return;
+
+ for (update_t &update : updates) {
+ if (update.packageName != patchPackageName)
+ continue;
+ if (update.basename != widePatchableFilename)
+ continue;
+
+ StringToHash(patchHashStr, update.downloadhash);
+
+ /* Replace the source URL with the patch file, mark it as
+ * patchable, and re-calculate download size */
+ totalFileSize -= (update.fileSize - size);
+ update.sourceURL = sourceURL;
+ update.fileSize = size;
+ update.patchable = true;
+ break;
+ }
+}
+
+static bool UpdateFile(update_t &file)
+{
+ wchar_t oldFileRenamedPath[MAX_PATH];
+
+ if (file.patchable)
+ Status(L"Updating %s...", file.outputPath.c_str());
+ else
+ Status(L"Installing %s...", file.outputPath.c_str());
+
+ /* Check if we're replacing an existing file or just installing a new
+ * one */
+ DWORD attribs = GetFileAttributes(file.outputPath.c_str());
+
+ if (attribs != INVALID_FILE_ATTRIBUTES) {
+ wchar_t *curFileName = nullptr;
+ wchar_t baseName[MAX_PATH];
+
+ StringCbCopy(baseName, sizeof(baseName),
+ file.outputPath.c_str());
+
+ curFileName = wcsrchr(baseName, '/');
+ if (curFileName) {
+ curFileName[0] = '\0';
+ curFileName++;
+ } else
+ curFileName = baseName;
+
+ /* Backup the existing file in case a rollback is needed */
+ StringCbCopy(oldFileRenamedPath,
+ sizeof(oldFileRenamedPath),
+ file.outputPath.c_str());
+ StringCbCat(oldFileRenamedPath,
+ sizeof(oldFileRenamedPath),
+ L".old");
+
+ if (!MyCopyFile(file.outputPath.c_str(), oldFileRenamedPath)) {
+ int is_sharing_violation =
+ (GetLastError() == ERROR_SHARING_VIOLATION);
+
+ if (is_sharing_violation)
+ Status(L"Update failed: %s is still in use. "
+ L"Close all programs and try again.",
+ curFileName);
+ else
+ Status(L"Update failed: Couldn't backup %s "
+ L"(error %d)",
+ curFileName, GetLastError());
+ return false;
+ }
+
+ int error_code;
+ bool installed_ok;
+
+ if (file.patchable) {
+ error_code = ApplyPatch(
+ file.tempPath.c_str(),
+ file.outputPath.c_str());
+ installed_ok = (error_code == 0);
+
+ if (installed_ok) {
+ BYTE patchedFileHash[BLAKE2_HASH_LENGTH];
+ if (!CalculateFileHash(file.outputPath.c_str(),
+ patchedFileHash)) {
+ Status(L"Update failed: Couldn't "
+ L"verify integrity of patched %s",
+ curFileName);
+ return false;
+ }
+
+ if (memcmp(file.hash, patchedFileHash,
+ BLAKE2_HASH_LENGTH) != 0) {
+ Status(L"Update failed: Integrity "
+ L"check of patched "
+ L"%s failed",
+ curFileName);
+ return false;
+ }
+ }
+ } else {
+ installed_ok = MyCopyFile(
+ file.tempPath.c_str(),
+ file.outputPath.c_str());
+ error_code = GetLastError();
+ }
+
+ if (!installed_ok) {
+ int is_sharing_violation =
+ (error_code == ERROR_SHARING_VIOLATION);
+
+ if (is_sharing_violation)
+ Status(L"Update failed: %s is still in use. "
+ L"Close all "
+ L"programs and try again.",
+ curFileName);
+ else
+ Status(L"Update failed: Couldn't update %s "
+ L"(error %d)",
+ curFileName,
+ GetLastError());
+ return false;
+ }
+
+ file.previousFile = oldFileRenamedPath;
+ file.state = STATE_INSTALLED;
+ } else {
+ if (file.patchable) {
+ /* Uh oh, we thought we could patch something but it's
+ * no longer there! */
+ Status(L"Update failed: Source file %s not found",
+ file.outputPath.c_str());
+ return false;
+ }
+
+ /* We may be installing into new folders,
+ * make sure they exist */
+ CreateFoldersForPath(file.outputPath.c_str());
+
+ bool success = !!MyCopyFile(
+ file.tempPath.c_str(),
+ file.outputPath.c_str());
+ if (!success) {
+ Status(L"Update failed: Couldn't install %s (error %d)",
+ file.outputPath.c_str(),
+ GetLastError());
+ return false;
+ }
+
+ file.previousFile = L"";
+ file.state = STATE_INSTALLED;
+ }
+
+ return true;
+}
+
+static wchar_t tempPath[MAX_PATH] = {};
+
+#define PATCH_MANIFEST_URL \
+ L"https://obsproject.com/update_studio/getpatchmanifest"
+#define HASH_NULL \
+ L"0000000000000000000000000000000000000000"
+
+static bool Update(wchar_t *cmdLine)
+{
+ /* ------------------------------------- *
+ * Check to make sure OBS isn't running */
+
+ HANDLE hObsUpdateMutex = OpenMutexW(SYNCHRONIZE, false,
+ L"OBSStudioUpdateMutex");
+ if (hObsUpdateMutex) {
+ HANDLE hWait[2];
+ hWait[0] = hObsUpdateMutex;
+ hWait[1] = cancelRequested;
+
+ int i = WaitForMultipleObjects(2, hWait, false, INFINITE);
+
+ if (i == WAIT_OBJECT_0)
+ ReleaseMutex(hObsUpdateMutex);
+
+ CloseHandle(hObsUpdateMutex);
+
+ if (i == WAIT_OBJECT_0 + 1)
+ return false;
+ }
+
+ if (!WaitForOBS())
+ return false;
+
+ /* ------------------------------------- *
+ * Init crypt stuff */
+
+ CryptProvider hProvider;
+ if (!CryptAcquireContext(&hProvider, nullptr, MS_ENH_RSA_AES_PROV,
+ PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
+ SetDlgItemTextW(hwndMain, IDC_STATUS,
+ L"Update failed: CryptAcquireContext failure");
+ return false;
+ }
+
+ ::hProvider = hProvider;
+
+ /* ------------------------------------- */
+
+ SetDlgItemTextW(hwndMain, IDC_STATUS,
+ L"Searching for available updates...");
+
+ /* ------------------------------------- *
+ * Check if updating portable build */
+
+ bool bIsPortable = false;
+
+ if (cmdLine[0]) {
+ int argc;
+ LPWSTR *argv = CommandLineToArgvW(cmdLine, &argc);
+
+ if (argv) {
+ for (int i = 0; i < argc; i++) {
+ if (wcscmp(argv[i], L"Portable") == 0) {
+ bIsPortable = true;
+ }
+ }
+
+ LocalFree((HLOCAL)argv);
+ }
+ }
+
+ /* ------------------------------------- *
+ * Get config path */
+
+ wchar_t lpAppDataPath[MAX_PATH];
+ lpAppDataPath[0] = 0;
+
+ if (bIsPortable) {
+ GetCurrentDirectory(_countof(lpAppDataPath), lpAppDataPath);
+ StringCbCat(lpAppDataPath, sizeof(lpAppDataPath), L"\\config");
+ } else {
+ CoTaskMemPtr pOut;
+ HRESULT hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData,
+ KF_FLAG_DEFAULT, nullptr, &pOut);
+ if (hr != S_OK) {
+ Status(L"Update failed: Could not determine AppData "
+ L"location");
+ return false;
+ }
+
+ StringCbCopy(lpAppDataPath, sizeof(lpAppDataPath), pOut);
+ StringCbCat(lpAppDataPath, sizeof(lpAppDataPath),
+ L"\\obs-studio");
+ }
+
+ /* ------------------------------------- *
+ * Get download path */
+
+ wchar_t manifestPath[MAX_PATH];
+ wchar_t tempDirName[MAX_PATH];
+
+ manifestPath[0] = 0;
+ tempDirName[0] = 0;
+
+ StringCbPrintf(manifestPath, sizeof(manifestPath),
+ L"%s\\updates\\manifest.json", lpAppDataPath);
+ if (!GetTempPathW(_countof(tempPath), tempPath)) {
+ Status(L"Update failed: Failed to get temp path: %ld",
+ GetLastError());
+ return false;
+ }
+ if (!GetTempFileNameW(tempDirName, L"obs-studio", 0, tempDirName)) {
+ Status(L"Update failed: Failed to create temp dir name: %ld",
+ GetLastError());
+ return false;
+ }
+
+ StringCbCat(tempPath, sizeof(tempPath), tempDirName);
+ CreateDirectory(tempPath, nullptr);
+
+ /* ------------------------------------- *
+ * Load manifest file */
+
+ Json root;
+ {
+ string manifestFile = QuickReadFile(manifestPath);
+ if (manifestFile.empty()) {
+ Status(L"Update failed: Couldn't load manifest file");
+ return false;
+ }
+
+ json_error_t error;
+ root = json_loads(manifestFile.c_str(), 0, &error);
+
+ if (!root) {
+ Status(L"Update failed: Couldn't parse update "
+ L"manifest: %S", error.text);
+ return false;
+ }
+ }
+
+ if (!json_is_object(root.get())) {
+ Status(L"Update failed: Invalid update manifest");
+ return false;
+ }
+
+ /* ------------------------------------- *
+ * Parse current manifest update files */
+
+ json_t *packages = json_object_get(root, "packages");
+ size_t packageCount = json_array_size(packages);
+
+ for (size_t i = 0; i < packageCount; i++) {
+ if (!AddPackageUpdateFiles(packages, i, tempPath)) {
+ Status(L"Failed to process update packages");
+ return false;
+ }
+ }
+
+ /* ------------------------------------- *
+ * Exit if updates already installed */
+
+ if (!updates.size()) {
+ Status(L"All available updates are already installed.");
+ return true;
+ }
+
+ /* ------------------------------------- *
+ * Generate file hash json */
+
+ Json files(json_array());
+
+ for (update_t &update : updates) {
+ wchar_t whash_string[BLAKE2_HASH_STR_LENGTH];
+ char hash_string[BLAKE2_HASH_STR_LENGTH];
+ char outputPath[MAX_PATH];
+
+ if (!update.has_hash)
+ continue;
+
+ /* check hash */
+ HashToString(update.my_hash, whash_string);
+ if (wcscmp(whash_string, HASH_NULL) == 0)
+ continue;
+
+ if (!WideToUTF8Buf(hash_string, whash_string))
+ continue;
+ if (!WideToUTF8Buf(outputPath, update.basename.c_str()))
+ continue;
+
+ string package_path;
+ package_path = update.packageName;
+ package_path += "/";
+ package_path += outputPath;
+
+ json_t *obj = json_object();
+ json_object_set(obj, "name", json_string(package_path.c_str()));
+ json_object_set(obj, "hash", json_string(hash_string));
+ json_array_append_new(files, obj);
+ }
+
+ /* ------------------------------------- *
+ * Send file hashes */
+
+ string newManifest;
+ {
+ char *post_body = json_dumps(files, JSON_COMPACT);
+
+ int responseCode;
+
+ int len = (int)strlen(post_body);
+ uLong compressSize = compressBound(len);
+ string compressedJson;
+
+ compressedJson.resize(compressSize);
+ compress2((Bytef*)&compressedJson[0], &compressSize,
+ (const Bytef*)post_body, len,
+ Z_BEST_COMPRESSION);
+ compressedJson.resize(compressSize);
+
+ bool success = !!HTTPPostData(PATCH_MANIFEST_URL,
+ (BYTE *)&compressedJson[0],
+ (int)compressedJson.size(),
+ L"Accept-Encoding: gzip", &responseCode,
+ newManifest);
+ free(post_body);
+
+ if (!success)
+ return false;
+
+ if (responseCode != 200) {
+ Status(L"Update failed: HTTP/%d while trying to "
+ L"download patch manifest",
+ responseCode);
+ return false;
+ }
+ }
+
+ /* ------------------------------------- *
+ * Parse new manifest */
+
+ json_error_t error;
+ root = json_loads(newManifest.c_str(), 0, &error);
+ if (!root) {
+ Status(L"Update failed: Couldn't parse patch manifest: %S",
+ error.text);
+ return false;
+ }
+
+ if (!json_is_array(root.get())) {
+ Status(L"Update failed: Invalid patch manifest");
+ return false;
+ }
+
+ packageCount = json_array_size(root);
+
+ for (size_t i = 0; i < packageCount; i++) {
+ json_t *patch = json_array_get(root, i);
+
+ if (!json_is_object(patch)) {
+ Status(L"Update failed: Invalid patch manifest");
+ return false;
+ }
+
+ json_t *name_json = json_object_get(patch, "name");
+ json_t *hash_json = json_object_get(patch, "hash");
+ json_t *source_json = json_object_get(patch, "source");
+ json_t *size_json = json_object_get(patch, "size");
+
+ if (!json_is_string(name_json))
+ continue;
+ if (!json_is_string(hash_json))
+ continue;
+ if (!json_is_string(source_json))
+ continue;
+ if (!json_is_integer(size_json))
+ continue;
+
+ const char *name = json_string_value(name_json);
+ const char *hash = json_string_value(hash_json);
+ const char *source = json_string_value(source_json);
+ int size = (int)json_integer_value(size_json);
+
+ UpdateWithPatchIfAvailable(name, hash, source, size);
+ }
+
+ /* ------------------------------------- *
+ * Download Updates */
+
+ if (!RunDownloadWorkers(2))
+ return false;
+
+ if (completedUpdates != updates.size()) {
+ Status(L"Update failed to download all files.");
+ return false;
+ }
+
+ /* ------------------------------------- *
+ * Install updates */
+
+ for (update_t &update : updates) {
+ if (!UpdateFile(update))
+ return false;
+ }
+
+ /* If we get here, all updates installed successfully so we can purge
+ * the old versions */
+ for (update_t &update : updates) {
+ if (!update.previousFile.empty())
+ DeleteFile(update.previousFile.c_str());
+
+ /* We delete here not above in case of duplicate hashes */
+ if (!update.tempPath.empty())
+ DeleteFile(update.tempPath.c_str());
+ }
+
+ Status(L"Update complete.");
+ SetDlgItemText(hwndMain, IDC_BUTTON, L"Launch OBS");
+ return true;
+}
+
+static DWORD WINAPI UpdateThread(void *arg)
+{
+ wchar_t *cmdLine = (wchar_t *)arg;
+
+ bool success = Update(cmdLine);
+
+ if (!success) {
+ /* This handles deleting temp files and rolling back and
+ * partially installed updates */
+ CleanupPartialUpdates();
+
+ if (tempPath[0])
+ RemoveDirectory(tempPath);
+
+ if (WaitForSingleObject(cancelRequested, 0) == WAIT_OBJECT_0)
+ Status(L"Update aborted.");
+
+ SendDlgItemMessage(hwndMain, IDC_PROGRESS, PBM_SETSTATE,
+ PBST_ERROR, 0);
+
+ SetDlgItemText(hwndMain, IDC_BUTTON, L"Exit");
+ EnableWindow(GetDlgItem(hwndMain, IDC_BUTTON), true);
+
+ updateFailed = true;
+ } else {
+ if (tempPath[0])
+ RemoveDirectory(tempPath);
+ }
+
+ if (bExiting)
+ ExitProcess(success);
+ return 0;
+}
+
+static void CancelUpdate(bool quit)
+{
+ if (WaitForSingleObject(updateThread, 0) != WAIT_OBJECT_0) {
+ bExiting = quit;
+ SetEvent(cancelRequested);
+ } else {
+ PostQuitMessage(0);
+ }
+}
+
+static void LaunchOBS()
+{
+ wchar_t cwd[MAX_PATH];
+ wchar_t newCwd[MAX_PATH];
+ wchar_t obsPath[MAX_PATH];
+
+ GetCurrentDirectory(_countof(cwd) - 1, cwd);
+
+ StringCbCopy(obsPath, sizeof(obsPath), cwd);
+ StringCbCat(obsPath, sizeof(obsPath), is32bit
+ ? L"\\bin\\32bit"
+ : L"\\bin\\64bit");
+ SetCurrentDirectory(obsPath);
+ StringCbCopy(newCwd, sizeof(newCwd), obsPath);
+
+ StringCbCat(obsPath, sizeof(obsPath), is32bit
+ ? L"\\obs32.exe"
+ : L"\\obs64.exe");
+
+ if (!FileExists(obsPath)) {
+ StringCbCopy(obsPath, sizeof(obsPath), cwd);
+ StringCbCat(obsPath, sizeof(obsPath), L"\\bin\\32bit");
+ SetCurrentDirectory(obsPath);
+ StringCbCopy(newCwd, sizeof(newCwd), obsPath);
+
+ StringCbCat(obsPath, sizeof(obsPath), L"\\obs32.exe");
+
+ if (!FileExists(obsPath)) {
+ /* TODO: give user a message maybe? */
+ return;
+ }
+ }
+
+ SHELLEXECUTEINFO execInfo;
+
+ ZeroMemory(&execInfo, sizeof(execInfo));
+
+ execInfo.cbSize = sizeof(execInfo);
+ execInfo.lpFile = obsPath;
+ execInfo.lpDirectory = newCwd;
+ execInfo.nShow = SW_SHOWNORMAL;
+
+ ShellExecuteEx(&execInfo);
+}
+
+static INT_PTR CALLBACK UpdateDialogProc(HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_INITDIALOG: {
+ static HICON hMainIcon = LoadIcon(hinstMain,
+ MAKEINTRESOURCE(IDI_ICON1));
+ SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hMainIcon);
+ SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hMainIcon);
+ return true;
+ }
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_BUTTON) {
+ if (HIWORD(wParam) == BN_CLICKED) {
+ DWORD result = WaitForSingleObject(
+ updateThread, 0);
+ if (result == WAIT_OBJECT_0) {
+ if (updateFailed)
+ PostQuitMessage(0);
+ else
+ PostQuitMessage(1);
+ } else {
+ EnableWindow((HWND)lParam, false);
+ CancelUpdate(false);
+ }
+ }
+ }
+ return true;
+
+ case WM_CLOSE:
+ CancelUpdate(true);
+ return true;
+ }
+
+ return false;
+}
+
+static void RestartAsAdmin(LPWSTR lpCmdLine)
+{
+ wchar_t myPath[MAX_PATH];
+ if (!GetModuleFileNameW(nullptr, myPath, _countof(myPath) - 1)) {
+ return;
+ }
+
+ wchar_t cwd[MAX_PATH];
+ GetCurrentDirectoryW(_countof(cwd) - 1, cwd);
+
+ SHELLEXECUTEINFO shExInfo = {0};
+ shExInfo.cbSize = sizeof(shExInfo);
+ shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
+ shExInfo.hwnd = 0;
+ shExInfo.lpVerb = L"runas"; /* Operation to perform */
+ shExInfo.lpFile = myPath; /* Application to start */
+ shExInfo.lpParameters = lpCmdLine; /* Additional parameters */
+ shExInfo.lpDirectory = cwd;
+ shExInfo.nShow = SW_NORMAL;
+ shExInfo.hInstApp = 0;
+
+ /* annoyingly the actual elevated updater will disappear behind other
+ * windows :( */
+ AllowSetForegroundWindow(ASFW_ANY);
+
+ if (ShellExecuteEx(&shExInfo)) {
+ DWORD exitCode;
+
+ if (GetExitCodeProcess(shExInfo.hProcess, &exitCode)) {
+ if (exitCode == 1) {
+ LaunchOBS();
+ }
+ }
+ CloseHandle(shExInfo.hProcess);
+ }
+}
+
+int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int)
+{
+ INITCOMMONCONTROLSEX icce;
+
+ if (!IsAppRunningAsAdminMode()) {
+ HANDLE hLowMutex = CreateMutexW(nullptr, true,
+ L"OBSUpdaterRunningAsNonAdminUser");
+
+ RestartAsAdmin(lpCmdLine);
+
+ if (hLowMutex) {
+ ReleaseMutex(hLowMutex);
+ CloseHandle(hLowMutex);
+ }
+
+ return 0;
+ } else {
+ {
+ wchar_t cwd[MAX_PATH];
+ wchar_t newPath[MAX_PATH];
+ GetCurrentDirectoryW(_countof(cwd) - 1, cwd);
+
+ is32bit = wcsstr(cwd, L"bin\\32bit") != nullptr;
+ StringCbCat(cwd, sizeof(cwd), L"\\..\\..");
+
+ GetFullPathName(cwd, _countof(newPath), newPath,
+ nullptr);
+ SetCurrentDirectory(newPath);
+ }
+
+ hinstMain = hInstance;
+
+ icce.dwSize = sizeof(icce);
+ icce.dwICC = ICC_PROGRESS_CLASS;
+
+ InitCommonControlsEx(&icce);
+
+ hwndMain = CreateDialog(hInstance,
+ MAKEINTRESOURCE(IDD_UPDATEDIALOG), nullptr,
+ UpdateDialogProc);
+ if (!hwndMain) {
+ return -1;
+ }
+
+ ShowWindow(hwndMain, SW_SHOWNORMAL);
+ SetForegroundWindow(hwndMain);
+
+ cancelRequested = CreateEvent(nullptr, true, false, nullptr);
+ updateThread = CreateThread(nullptr, 0, UpdateThread,
+ lpCmdLine, 0, nullptr);
+
+ MSG msg;
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ if (!IsDialogMessage(hwndMain, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ /* there is no non-elevated process waiting for us if UAC is
+ * disabled */
+ WinHandle hMutex = OpenMutex(SYNCHRONIZE, false,
+ L"OBSUpdaterRunningAsNonAdminUser");
+ if (msg.wParam == 1 && !hMutex) {
+ LaunchOBS();
+ }
+
+ return (int)msg.wParam;
+ }
+}
diff --git a/UI/win-update/updater/updater.hpp b/UI/win-update/updater/updater.hpp
new file mode 100644
index 0000000..5f1abd7
--- /dev/null
+++ b/UI/win-update/updater/updater.hpp
@@ -0,0 +1,103 @@
+#pragma once
+
+#define WINVER 0x0600
+#define _WIN32_WINDOWS 0x0600
+#define _WIN32_WINNT 0x0600
+#define WIN32_LEAN_AND_MEAN
+
+#define ZLIB_CONST
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "../win-update-helpers.hpp"
+
+#define BLAKE2_HASH_LENGTH 20
+#define BLAKE2_HASH_STR_LENGTH ((BLAKE2_HASH_LENGTH * 2) + 1)
+
+#if defined _M_IX86
+#pragma comment(linker, \
+ "/manifestdependency:\"type='win32' " \
+ "name='Microsoft.Windows.Common-Controls' " \
+ "version='6.0.0.0' " \
+ "processorArchitecture='x86' " \
+ "publicKeyToken='6595b64144ccf1df' " \
+ "language='*'\"")
+#elif defined _M_IA64
+#pragma comment(linker, \
+ "/manifestdependency:\"type='win32' " \
+ "name='Microsoft.Windows.Common-Controls' " \
+ "version='6.0.0.0' " \
+ "processorArchitecture='ia64' " \
+ "publicKeyToken='6595b64144ccf1df' " \
+ "language='*'\"")
+#elif defined _M_X64
+#pragma comment(linker, \
+ "/manifestdependency:\"type='win32' " \
+ "name='Microsoft.Windows.Common-Controls' " \
+ "version='6.0.0.0' " \
+ "processorArchitecture='amd64' " \
+ "publicKeyToken='6595b64144ccf1df' " \
+ "language='*'\"")
+#else
+#pragma comment(linker, \
+ "/manifestdependency:\"type='win32' " \
+ "name='Microsoft.Windows.Common-Controls' " \
+ "version='6.0.0.0' processorArchitecture='*' " \
+ "publicKeyToken='6595b64144ccf1df' " \
+ "language='*'\"")
+#endif
+
+#include
+#include
+#include "resource.h"
+
+bool HTTPGetFile(HINTERNET hConnect,
+ const wchar_t *url,
+ const wchar_t *outputPath,
+ const wchar_t *extraHeaders,
+ int * responseCode);
+bool HTTPPostData(const wchar_t *url,
+ const BYTE * data,
+ int dataLen,
+ const wchar_t *extraHeaders,
+ int * responseCode,
+ std::string & response);
+
+void HashToString(const BYTE *in, wchar_t *out);
+void StringToHash(const wchar_t *in, BYTE *out);
+
+bool CalculateFileHash(const wchar_t *path, BYTE *hash);
+
+int ApplyPatch(LPCTSTR patchFile, LPCTSTR targetFile);
+
+extern HWND hwndMain;
+extern HCRYPTPROV hProvider;
+extern int totalFileSize;
+extern int completedFileSize;
+extern HANDLE cancelRequested;
+
+#pragma pack(push, r1, 1)
+
+typedef struct {
+ BLOBHEADER blobheader;
+ RSAPUBKEY rsapubkey;
+} PUBLICKEYHEADER;
+
+#pragma pack(pop, r1)
+
+void FreeWinHttpHandle(HINTERNET handle);
+using HttpHandle = CustomHandle;
diff --git a/UI/win-update/updater/updater.rc b/UI/win-update/updater/updater.rc
new file mode 100644
index 0000000..c099f5c
--- /dev/null
+++ b/UI/win-update/updater/updater.rc
@@ -0,0 +1,145 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_UPDATEDIALOG DIALOGEX 0, 0, 316, 56
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "OBS Studio Update"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Cancel",IDC_BUTTON,259,34,50,14
+ CONTROL "",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH,7,17,302,14
+ LTEXT "Waiting for OBS to exit...",IDC_STATUS,7,7,302,8,SS_WORDELLIPSIS
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_UPDATEDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 309
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 48
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "obsproject.com"
+ VALUE "FileDescription", "OBS Updater"
+ VALUE "FileVersion", "1.0.0.1"
+ VALUE "InternalName", "updater.exe"
+ VALUE "LegalCopyright", "Copyright (C) 2013 Richard Stanway"
+ VALUE "OriginalFilename", "updater.exe"
+ VALUE "ProductName", "OBS Updater"
+ VALUE "ProductVersion", "1.0.0.1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1 ICON "../../../cmake/winrc/obs-studio.ico"
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/UI/win-update/win-update-helpers.cpp b/UI/win-update/win-update-helpers.cpp
new file mode 100644
index 0000000..b969e32
--- /dev/null
+++ b/UI/win-update/win-update-helpers.cpp
@@ -0,0 +1,40 @@
+#include "win-update-helpers.hpp"
+
+void FreeProvider(HCRYPTPROV prov)
+{
+ CryptReleaseContext(prov, 0);
+}
+
+void FreeHash(HCRYPTHASH hash)
+{
+ CryptDestroyHash(hash);
+}
+
+void FreeKey(HCRYPTKEY key)
+{
+ CryptDestroyKey(key);
+}
+
+std::string vstrprintf(const char *format, va_list args)
+{
+ if (!format)
+ return std::string();
+
+ std::string str;
+ int size = (int)vsnprintf(nullptr, 0, format, args);
+ str.resize(size);
+ vsnprintf(&str[0], size, format, args);
+ return str;
+}
+
+std::string strprintf(const char *format, ...)
+{
+ std::string str;
+ va_list args;
+
+ va_start(args, format);
+ str = vstrprintf(format, args);
+ va_end(args);
+
+ return str;
+}
diff --git a/UI/win-update/win-update-helpers.hpp b/UI/win-update/win-update-helpers.hpp
new file mode 100644
index 0000000..51ea16a
--- /dev/null
+++ b/UI/win-update/win-update-helpers.hpp
@@ -0,0 +1,139 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+
+#include
+
+#include
+#include
+
+/* ------------------------------------------------------------------------ */
+
+template class CustomHandle {
+ T handle;
+
+public:
+ inline CustomHandle() : handle(0) {}
+ inline CustomHandle(T in) : handle(in) {}
+ inline ~CustomHandle()
+ {
+ if (handle)
+ freefunc(handle);
+ }
+
+ inline T *operator&() {return &handle;}
+ inline operator T() const {return handle;}
+ inline T get() const {return handle;}
+
+ inline CustomHandle &operator=(T in)
+ {
+ if (handle)
+ freefunc(handle);
+ handle = in;
+ return *this;
+ }
+
+ inline bool operator!() const {return !handle;}
+};
+
+void FreeProvider(HCRYPTPROV prov);
+void FreeHash(HCRYPTHASH hash);
+void FreeKey(HCRYPTKEY key);
+
+using CryptProvider = CustomHandle;
+using CryptHash = CustomHandle;
+using CryptKey = CustomHandle;
+
+/* ------------------------------------------------------------------------ */
+
+template class LocalPtr {
+ T *ptr = nullptr;
+
+public:
+ inline ~LocalPtr()
+ {
+ if (ptr)
+ LocalFree(ptr);
+ }
+
+ inline T **operator&() {return &ptr;}
+ inline operator T() const {return ptr;}
+ inline T *get() const {return ptr;}
+
+ inline bool operator!() const {return !ptr;}
+
+ inline T *operator->() {return ptr;}
+};
+
+/* ------------------------------------------------------------------------ */
+
+class Json {
+ json_t *json;
+
+public:
+ inline Json() : json(nullptr) {}
+ explicit inline Json(json_t *json_) : json(json_) {}
+ inline Json(const Json &from) : json(json_incref(from.json)) {}
+ inline Json(Json &&from) : json(from.json) {from.json = nullptr;}
+
+ inline ~Json() {
+ if (json)
+ json_decref(json);
+ }
+
+ inline Json &operator=(json_t *json_)
+ {
+ if (json)
+ json_decref(json);
+ json = json_;
+ return *this;
+ }
+ inline Json &operator=(const Json &from)
+ {
+ if (json)
+ json_decref(json);
+ json = json_incref(from.json);
+ return *this;
+ }
+ inline Json &operator=(Json &&from)
+ {
+ if (json)
+ json_decref(json);
+ json = from.json;
+ from.json = nullptr;
+ return *this;
+ }
+
+ inline operator json_t *() const {return json;}
+
+ inline bool operator!() const {return !json;}
+
+ inline const char *GetString(const char *name,
+ const char *def = nullptr) const
+ {
+ json_t *obj(json_object_get(json, name));
+ if (!obj)
+ return def;
+ return json_string_value(obj);
+ }
+ inline int64_t GetInt(const char *name, int def = 0) const
+ {
+ json_t *obj(json_object_get(json, name));
+ if (!obj)
+ return def;
+ return json_integer_value(obj);
+ }
+ inline json_t *GetObject(const char *name) const
+ {
+ return json_object_get(json, name);
+ }
+
+ inline json_t *get() const {return json;}
+};
+
+/* ------------------------------------------------------------------------ */
+
+std::string vstrprintf(const char *format, va_list args);
+std::string strprintf(const char *format, ...);
diff --git a/UI/win-update/win-update.cpp b/UI/win-update/win-update.cpp
new file mode 100644
index 0000000..6cfec73
--- /dev/null
+++ b/UI/win-update/win-update.cpp
@@ -0,0 +1,781 @@
+#include "win-update-helpers.hpp"
+#include "update-window.hpp"
+#include "remote-text.hpp"
+#include "win-update.hpp"
+#include "obs-app.hpp"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+/* ------------------------------------------------------------------------ */
+
+#ifndef WIN_MANIFEST_URL
+#define WIN_MANIFEST_URL "https://obsproject.com/update_studio/manifest.json"
+#endif
+
+#ifndef WIN_UPDATER_URL
+#define WIN_UPDATER_URL "https://obsproject.com/update_studio/updater.exe"
+#endif
+
+static HCRYPTPROV provider = 0;
+
+#pragma pack(push, r1, 1)
+
+typedef struct {
+ BLOBHEADER blobheader;
+ RSAPUBKEY rsapubkey;
+} PUBLICKEYHEADER;
+
+#pragma pack(pop, r1)
+
+#define BLAKE2_HASH_LENGTH 20
+#define BLAKE2_HASH_STR_LENGTH ((BLAKE2_HASH_LENGTH * 2) + 1)
+
+#define TEST_BUILD
+
+// Hard coded 4096 bit RSA public key for obsproject.com in PEM format
+static const unsigned char obs_pub[] = {
+ 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50,
+ 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d,
+ 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x6a, 0x41, 0x4e, 0x42,
+ 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, 0x30, 0x42, 0x41,
+ 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f, 0x43, 0x41, 0x67, 0x38, 0x41, 0x4d,
+ 0x49, 0x49, 0x43, 0x43, 0x67, 0x4b, 0x43, 0x41, 0x67, 0x45, 0x41, 0x6c,
+ 0x33, 0x73, 0x76, 0x65, 0x72, 0x77, 0x39, 0x48, 0x51, 0x2b, 0x72, 0x59,
+ 0x51, 0x4e, 0x6e, 0x39, 0x43, 0x61, 0x37, 0x0a, 0x39, 0x4c, 0x55, 0x36,
+ 0x32, 0x6e, 0x47, 0x36, 0x4e, 0x6f, 0x7a, 0x45, 0x2f, 0x46, 0x73, 0x49,
+ 0x56, 0x4e, 0x65, 0x72, 0x2b, 0x57, 0x2f, 0x68, 0x75, 0x65, 0x45, 0x38,
+ 0x57, 0x51, 0x31, 0x6d, 0x72, 0x46, 0x50, 0x2b, 0x32, 0x79, 0x41, 0x2b,
+ 0x69, 0x59, 0x52, 0x75, 0x74, 0x59, 0x50, 0x65, 0x45, 0x67, 0x70, 0x78,
+ 0x74, 0x6f, 0x64, 0x48, 0x68, 0x67, 0x6b, 0x52, 0x34, 0x70, 0x45, 0x4b,
+ 0x0a, 0x56, 0x6e, 0x72, 0x72, 0x31, 0x38, 0x71, 0x34, 0x73, 0x7a, 0x6c,
+ 0x76, 0x38, 0x39, 0x51, 0x49, 0x37, 0x74, 0x38, 0x6c, 0x4d, 0x6f, 0x4c,
+ 0x54, 0x6c, 0x46, 0x2b, 0x74, 0x31, 0x49, 0x52, 0x30, 0x56, 0x34, 0x77,
+ 0x4a, 0x56, 0x33, 0x34, 0x49, 0x33, 0x43, 0x2b, 0x33, 0x35, 0x39, 0x4b,
+ 0x69, 0x78, 0x6e, 0x7a, 0x4c, 0x30, 0x42, 0x6c, 0x39, 0x61, 0x6a, 0x2f,
+ 0x7a, 0x44, 0x63, 0x72, 0x58, 0x0a, 0x57, 0x6c, 0x35, 0x70, 0x48, 0x54,
+ 0x69, 0x6f, 0x4a, 0x77, 0x59, 0x4f, 0x67, 0x4d, 0x69, 0x42, 0x47, 0x4c,
+ 0x79, 0x50, 0x65, 0x69, 0x74, 0x4d, 0x46, 0x64, 0x6a, 0x6a, 0x54, 0x49,
+ 0x70, 0x43, 0x4d, 0x2b, 0x6d, 0x78, 0x54, 0x57, 0x58, 0x43, 0x72, 0x5a,
+ 0x39, 0x64, 0x50, 0x55, 0x4b, 0x76, 0x5a, 0x74, 0x67, 0x7a, 0x6a, 0x64,
+ 0x2b, 0x49, 0x7a, 0x6c, 0x48, 0x69, 0x64, 0x48, 0x74, 0x4f, 0x0a, 0x4f,
+ 0x52, 0x42, 0x4e, 0x35, 0x6d, 0x52, 0x73, 0x38, 0x4c, 0x4e, 0x4f, 0x35,
+ 0x38, 0x6b, 0x37, 0x39, 0x72, 0x37, 0x37, 0x44, 0x63, 0x67, 0x51, 0x59,
+ 0x50, 0x4e, 0x69, 0x69, 0x43, 0x74, 0x57, 0x67, 0x43, 0x2b, 0x59, 0x34,
+ 0x4b, 0x37, 0x75, 0x53, 0x5a, 0x58, 0x33, 0x48, 0x76, 0x65, 0x6f, 0x6d,
+ 0x32, 0x74, 0x48, 0x62, 0x56, 0x58, 0x79, 0x30, 0x4c, 0x2f, 0x43, 0x6c,
+ 0x37, 0x66, 0x4d, 0x0a, 0x48, 0x4b, 0x71, 0x66, 0x63, 0x51, 0x47, 0x75,
+ 0x79, 0x72, 0x76, 0x75, 0x64, 0x34, 0x32, 0x4f, 0x72, 0x57, 0x61, 0x72,
+ 0x41, 0x73, 0x6e, 0x32, 0x70, 0x32, 0x45, 0x69, 0x36, 0x4b, 0x7a, 0x78,
+ 0x62, 0x33, 0x47, 0x36, 0x45, 0x53, 0x43, 0x77, 0x31, 0x35, 0x6e, 0x48,
+ 0x41, 0x67, 0x4c, 0x61, 0x6c, 0x38, 0x7a, 0x53, 0x71, 0x37, 0x2b, 0x72,
+ 0x61, 0x45, 0x2f, 0x78, 0x6b, 0x4c, 0x70, 0x43, 0x0a, 0x62, 0x59, 0x67,
+ 0x35, 0x67, 0x6d, 0x59, 0x36, 0x76, 0x62, 0x6d, 0x57, 0x6e, 0x71, 0x39,
+ 0x64, 0x71, 0x57, 0x72, 0x55, 0x7a, 0x61, 0x71, 0x4f, 0x66, 0x72, 0x5a,
+ 0x50, 0x67, 0x76, 0x67, 0x47, 0x30, 0x57, 0x76, 0x6b, 0x42, 0x53, 0x68,
+ 0x66, 0x61, 0x45, 0x4f, 0x42, 0x61, 0x49, 0x55, 0x78, 0x41, 0x33, 0x51,
+ 0x42, 0x67, 0x7a, 0x41, 0x5a, 0x68, 0x71, 0x65, 0x65, 0x64, 0x46, 0x39,
+ 0x68, 0x0a, 0x61, 0x66, 0x4d, 0x47, 0x4d, 0x4d, 0x39, 0x71, 0x56, 0x62,
+ 0x66, 0x77, 0x75, 0x75, 0x7a, 0x4a, 0x32, 0x75, 0x68, 0x2b, 0x49, 0x6e,
+ 0x61, 0x47, 0x61, 0x65, 0x48, 0x32, 0x63, 0x30, 0x34, 0x6f, 0x56, 0x63,
+ 0x44, 0x46, 0x66, 0x65, 0x4f, 0x61, 0x44, 0x75, 0x78, 0x52, 0x6a, 0x43,
+ 0x43, 0x62, 0x71, 0x72, 0x35, 0x73, 0x4c, 0x53, 0x6f, 0x31, 0x43, 0x57,
+ 0x6f, 0x6b, 0x79, 0x6e, 0x6a, 0x4e, 0x0a, 0x43, 0x42, 0x2b, 0x62, 0x32,
+ 0x72, 0x51, 0x46, 0x37, 0x44, 0x50, 0x50, 0x62, 0x44, 0x34, 0x73, 0x2f,
+ 0x6e, 0x54, 0x39, 0x4e, 0x73, 0x63, 0x6b, 0x2f, 0x4e, 0x46, 0x7a, 0x72,
+ 0x42, 0x58, 0x52, 0x4f, 0x2b, 0x64, 0x71, 0x6b, 0x65, 0x42, 0x77, 0x44,
+ 0x55, 0x43, 0x76, 0x37, 0x62, 0x5a, 0x67, 0x57, 0x37, 0x4f, 0x78, 0x75,
+ 0x4f, 0x58, 0x30, 0x37, 0x4c, 0x54, 0x71, 0x66, 0x70, 0x35, 0x73, 0x0a,
+ 0x4f, 0x65, 0x47, 0x67, 0x75, 0x62, 0x75, 0x62, 0x69, 0x77, 0x59, 0x33,
+ 0x55, 0x64, 0x48, 0x59, 0x71, 0x2b, 0x4c, 0x39, 0x4a, 0x71, 0x49, 0x53,
+ 0x47, 0x31, 0x74, 0x4d, 0x34, 0x48, 0x65, 0x4b, 0x6a, 0x61, 0x48, 0x6a,
+ 0x75, 0x31, 0x4d, 0x44, 0x6a, 0x76, 0x48, 0x5a, 0x32, 0x44, 0x62, 0x6d,
+ 0x4c, 0x77, 0x55, 0x78, 0x75, 0x59, 0x61, 0x36, 0x4a, 0x5a, 0x44, 0x4b,
+ 0x57, 0x73, 0x37, 0x72, 0x0a, 0x49, 0x72, 0x64, 0x44, 0x77, 0x78, 0x33,
+ 0x4a, 0x77, 0x61, 0x63, 0x46, 0x36, 0x36, 0x68, 0x33, 0x59, 0x55, 0x57,
+ 0x36, 0x74, 0x7a, 0x55, 0x5a, 0x68, 0x7a, 0x74, 0x63, 0x6d, 0x51, 0x65,
+ 0x70, 0x50, 0x2f, 0x75, 0x37, 0x42, 0x67, 0x47, 0x72, 0x6b, 0x4f, 0x50,
+ 0x50, 0x70, 0x59, 0x41, 0x30, 0x4e, 0x45, 0x4a, 0x38, 0x30, 0x53, 0x65,
+ 0x41, 0x78, 0x37, 0x68, 0x69, 0x4e, 0x34, 0x76, 0x61, 0x0a, 0x65, 0x45,
+ 0x51, 0x4b, 0x6e, 0x52, 0x6e, 0x2b, 0x45, 0x70, 0x42, 0x4e, 0x36, 0x55,
+ 0x42, 0x61, 0x35, 0x66, 0x37, 0x4c, 0x6f, 0x4b, 0x38, 0x43, 0x41, 0x77,
+ 0x45, 0x41, 0x41, 0x51, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+ 0x45, 0x4e, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b,
+ 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a
+};
+static const unsigned int obs_pub_len = 800;
+
+/* ------------------------------------------------------------------------ */
+
+static bool QuickWriteFile(const char *file, const void *data, size_t size)
+try {
+ BPtr w_file;
+ if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0)
+ return false;
+
+ WinHandle handle = CreateFileW(
+ w_file,
+ GENERIC_WRITE,
+ 0,
+ nullptr,
+ CREATE_ALWAYS,
+ FILE_FLAG_WRITE_THROUGH,
+ nullptr);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ throw strprintf("Failed to open file '%s': %lu",
+ file, GetLastError());
+
+ DWORD written;
+ if (!WriteFile(handle, data, (DWORD)size, &written, nullptr))
+ throw strprintf("Failed to write file '%s': %lu",
+ file, GetLastError());
+
+ return true;
+
+} catch (string text) {
+ blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
+ return false;
+}
+
+static bool QuickReadFile(const char *file, string &data)
+try {
+ BPtr w_file;
+ if (os_utf8_to_wcs_ptr(file, 0, &w_file) == 0)
+ return false;
+
+ WinHandle handle = CreateFileW(
+ w_file,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ nullptr,
+ OPEN_EXISTING,
+ 0,
+ nullptr);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ throw strprintf("Failed to open file '%s': %lu",
+ file, GetLastError());
+
+ DWORD size = GetFileSize(handle, nullptr);
+ data.resize(size);
+
+ DWORD read;
+ if (!ReadFile(handle, &data[0], size, &read, nullptr))
+ throw strprintf("Failed to write file '%s': %lu",
+ file, GetLastError());
+
+ return true;
+
+} catch (string text) {
+ blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
+ return false;
+}
+
+static void HashToString(const uint8_t *in, char *out)
+{
+ const char alphabet[] = "0123456789abcdef";
+
+ for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) {
+ out[2 * i] = alphabet[in[i] / 16];
+ out[2 * i + 1] = alphabet[in[i] % 16];
+ }
+
+ out[BLAKE2_HASH_LENGTH * 2] = 0;
+}
+
+static bool CalculateFileHash(const char *path, uint8_t *hash)
+try {
+ blake2b_state blake2;
+ if (blake2b_init(&blake2, BLAKE2_HASH_LENGTH) != 0)
+ return false;
+
+ BPtr w_path;
+ if (os_utf8_to_wcs_ptr(path, 0, &w_path) == 0)
+ return false;
+
+ WinHandle handle = CreateFileW(w_path, GENERIC_READ, FILE_SHARE_READ,
+ nullptr, OPEN_EXISTING, 0, nullptr);
+ if (handle == INVALID_HANDLE_VALUE)
+ throw strprintf("Failed to open file '%s': %lu",
+ path, GetLastError());
+
+ vector buf;
+ buf.resize(65536);
+
+ for (;;) {
+ DWORD read = 0;
+ if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read,
+ nullptr))
+ throw strprintf("Failed to read file '%s': %lu",
+ path, GetLastError());
+
+ if (!read)
+ break;
+
+ if (blake2b_update(&blake2, buf.data(), read) != 0)
+ return false;
+ }
+
+ if (blake2b_final(&blake2, hash, BLAKE2_HASH_LENGTH) != 0)
+ return false;
+
+ return true;
+
+} catch (string text) {
+ blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
+ return false;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static bool VerifyDigitalSignature(uint8_t *buf, size_t len, uint8_t *sig,
+ size_t sigLen)
+{
+ /* ASN of PEM public key */
+ BYTE binaryKey[1024];
+ DWORD binaryKeyLen = sizeof(binaryKey);
+
+ /* Windows X509 public key info from ASN */
+ LocalPtr publicPBLOB;
+ DWORD iPBLOBSize;
+
+ /* RSA BLOB info from X509 public key */
+ LocalPtr rsaPublicBLOB;
+ DWORD rsaPublicBLOBSize;
+
+ /* Handle to public key */
+ CryptKey keyOut;
+
+ /* Handle to hash context */
+ CryptHash hash;
+
+ /* Signature in little-endian format */
+ vector reversedSig;
+
+ if (!CryptStringToBinaryA((LPCSTR)obs_pub,
+ obs_pub_len,
+ CRYPT_STRING_BASE64HEADER,
+ binaryKey,
+ &binaryKeyLen,
+ nullptr,
+ nullptr))
+ return false;
+
+ if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
+ X509_PUBLIC_KEY_INFO,
+ binaryKey,
+ binaryKeyLen,
+ CRYPT_ENCODE_ALLOC_FLAG,
+ nullptr,
+ &publicPBLOB,
+ &iPBLOBSize))
+ return false;
+
+ if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
+ RSA_CSP_PUBLICKEYBLOB,
+ publicPBLOB->PublicKey.pbData,
+ publicPBLOB->PublicKey.cbData,
+ CRYPT_ENCODE_ALLOC_FLAG,
+ nullptr,
+ &rsaPublicBLOB,
+ &rsaPublicBLOBSize))
+ return false;
+
+ if (!CryptImportKey(provider,
+ (const BYTE *)rsaPublicBLOB.get(),
+ rsaPublicBLOBSize,
+ 0,
+ 0,
+ &keyOut))
+ return false;
+
+ if (!CryptCreateHash(provider, CALG_SHA_512, 0, 0, &hash))
+ return false;
+
+ if (!CryptHashData(hash, buf, (DWORD)len, 0))
+ return false;
+
+ /* Windows requires signature in little-endian. Every other crypto
+ * provider is big-endian of course. */
+ reversedSig.resize(sigLen);
+ for (size_t i = 0; i < sigLen; i++)
+ reversedSig[i] = sig[sigLen - i - 1];
+
+ if (!CryptVerifySignature(hash,
+ reversedSig.data(),
+ (DWORD)sigLen,
+ keyOut,
+ nullptr,
+ 0))
+ return false;
+
+ return true;
+}
+
+static inline void HexToByteArray(const char *hexStr, size_t hexLen,
+ vector &out)
+{
+ char ptr[3];
+
+ ptr[2] = 0;
+
+ for (size_t i = 0; i < hexLen; i += 2) {
+ ptr[0] = hexStr[i];
+ ptr[1] = hexStr[i + 1];
+ out.push_back((uint8_t)strtoul(ptr, nullptr, 16));
+ }
+}
+
+static bool CheckDataSignature(const string &data, const char *name,
+ const char *hexSig, size_t sigLen)
+try {
+ if (sigLen == 0 || sigLen > 0xFFFF || (sigLen & 1) != 0)
+ throw strprintf("Missing or invalid signature for %s", name);
+
+ /* Convert TCHAR signature to byte array */
+ vector signature;
+ signature.reserve(sigLen);
+ HexToByteArray(hexSig, sigLen, signature);
+
+ if (!VerifyDigitalSignature((uint8_t*)data.data(),
+ data.size(),
+ signature.data(),
+ signature.size()))
+ throw strprintf("Signature check failed for %s", name);
+
+ return true;
+
+} catch (string text) {
+ blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
+ return false;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static bool FetchUpdaterModule(const char *url)
+try {
+ long responseCode;
+ uint8_t updateFileHash[BLAKE2_HASH_LENGTH];
+ vector extraHeaders;
+
+ BPtr updateFilePath = GetConfigPathPtr(
+ "obs-studio\\updates\\updater.exe");
+
+ if (CalculateFileHash(updateFilePath, updateFileHash)) {
+ char hashString[BLAKE2_HASH_STR_LENGTH];
+ HashToString(updateFileHash, hashString);
+
+ string header = "If-None-Match: ";
+ header += hashString;
+ extraHeaders.push_back(move(header));
+ }
+
+ string signature;
+ string error;
+ string data;
+
+ bool success = GetRemoteFile(url, data, error, &responseCode,
+ nullptr, nullptr, extraHeaders, &signature);
+
+ if (!success || (responseCode != 200 && responseCode != 304)) {
+ if (responseCode == 404)
+ return false;
+
+ throw strprintf("Could not fetch '%s': %s", url, error.c_str());
+ }
+
+ /* A new file must be digitally signed */
+ if (responseCode == 200) {
+ bool valid = CheckDataSignature(data, url, signature.data(),
+ signature.size());
+ if (!valid)
+ throw string("Invalid updater module signature");
+
+ if (!QuickWriteFile(updateFilePath, data.data(), data.size()))
+ return false;
+ }
+
+ return true;
+
+} catch (string text) {
+ blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
+ return false;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static bool ParseUpdateManifest(const char *manifest, bool *updatesAvailable,
+ string ¬es_str, int &updateVer)
+try {
+
+ json_error_t error;
+ Json root(json_loads(manifest, 0, &error));
+ if (!root)
+ throw strprintf("Failed reading json string (%d): %s",
+ error.line, error.text);
+
+ if (!json_is_object(root.get()))
+ throw string("Root of manifest is not an object");
+
+ int major = root.GetInt("version_major");
+ int minor = root.GetInt("version_minor");
+ int patch = root.GetInt("version_patch");
+
+ if (major == 0)
+ throw strprintf("Invalid version number: %d.%d.%d",
+ major,
+ minor,
+ patch);
+
+ json_t *notes = json_object_get(root, "notes");
+ if (!json_is_string(notes))
+ throw string("'notes' value invalid");
+
+ notes_str = json_string_value(notes);
+
+ json_t *packages = json_object_get(root, "packages");
+ if (!json_is_array(packages))
+ throw string("'packages' value invalid");
+
+ int cur_ver = LIBOBS_API_VER;
+ int new_ver = MAKE_SEMANTIC_VERSION(major, minor, patch);
+
+ updateVer = new_ver;
+ *updatesAvailable = new_ver > cur_ver;
+
+ return true;
+
+} catch (string text) {
+ blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
+ return false;
+}
+
+/* ------------------------------------------------------------------------ */
+
+void GenerateGUID(string &guid)
+{
+ BYTE junk[20];
+
+ if (!CryptGenRandom(provider, sizeof(junk), junk))
+ return;
+
+ guid.resize(41);
+ HashToString(junk, &guid[0]);
+}
+
+void AutoUpdateThread::infoMsg(const QString &title, const QString &text)
+{
+ QMessageBox::information(App()->GetMainWindow(), title, text);
+}
+
+void AutoUpdateThread::info(const QString &title, const QString &text)
+{
+ QMetaObject::invokeMethod(this, "infoMsg",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(QString, title),
+ Q_ARG(QString, text));
+}
+
+int AutoUpdateThread::queryUpdateSlot(bool manualUpdate, const QString &text)
+{
+ OBSUpdate updateDlg(App()->GetMainWindow(), manualUpdate, text);
+ return updateDlg.exec();
+}
+
+int AutoUpdateThread::queryUpdate(bool manualUpdate, const char *text_utf8)
+{
+ int ret = OBSUpdate::No;
+ QString text = text_utf8;
+ QMetaObject::invokeMethod(this, "queryUpdateSlot",
+ Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(int, ret),
+ Q_ARG(bool, manualUpdate),
+ Q_ARG(QString, text));
+ return ret;
+}
+
+static bool IsFileInUse(const wstring &file)
+{
+ WinHandle f = CreateFile(file.c_str(), GENERIC_WRITE, 0, nullptr,
+ OPEN_EXISTING, 0, nullptr);
+ if (!f.Valid()) {
+ int err = GetLastError();
+ if (err == ERROR_SHARING_VIOLATION ||
+ err == ERROR_LOCK_VIOLATION)
+ return true;
+ }
+
+ return false;
+}
+
+static bool IsGameCaptureInUse()
+{
+ wstring path = L"..\\..\\data\\obs-plugins\\win-capture\\graphics-hook";
+ return IsFileInUse(path + L"32.dll") ||
+ IsFileInUse(path + L"64.dll");
+}
+
+void AutoUpdateThread::run()
+try {
+ long responseCode;
+ vector extraHeaders;
+ string text;
+ string error;
+ string signature;
+ CryptProvider provider;
+ BYTE manifestHash[BLAKE2_HASH_LENGTH];
+ bool updatesAvailable = false;
+ bool success;
+
+ struct FinishedTrigger {
+ inline ~FinishedTrigger()
+ {
+ QMetaObject::invokeMethod(App()->GetMainWindow(),
+ "updateCheckFinished");
+ }
+ } finishedTrigger;
+
+ BPtr manifestPath = GetConfigPathPtr(
+ "obs-studio\\updates\\manifest.json");
+
+ auto ActiveOrGameCaptureLocked = [this] ()
+ {
+ if (video_output_active(obs_get_video())) {
+ if (manualUpdate)
+ info(QTStr("Updater.Running.Title"),
+ QTStr("Updater.Running.Text"));
+ return true;
+ }
+ if (IsGameCaptureInUse()) {
+ if (manualUpdate)
+ info(QTStr("Updater.GameCaptureActive.Title"),
+ QTStr("Updater.GameCaptureActive.Text"));
+ return true;
+ }
+
+ return false;
+ };
+
+ /* ----------------------------------- *
+ * warn if running or gc locked */
+
+ if (ActiveOrGameCaptureLocked())
+ return;
+
+ /* ----------------------------------- *
+ * create signature provider */
+
+ if (!CryptAcquireContext(&provider,
+ nullptr,
+ MS_ENH_RSA_AES_PROV,
+ PROV_RSA_AES,
+ CRYPT_VERIFYCONTEXT))
+ throw strprintf("CryptAcquireContext failed: %lu",
+ GetLastError());
+
+ ::provider = provider;
+
+ /* ----------------------------------- *
+ * avoid downloading manifest again */
+
+ if (CalculateFileHash(manifestPath, manifestHash)) {
+ char hashString[BLAKE2_HASH_STR_LENGTH];
+ HashToString(manifestHash, hashString);
+
+ string header = "If-None-Match: ";
+ header += hashString;
+ extraHeaders.push_back(move(header));
+ }
+
+ /* ----------------------------------- *
+ * get current install GUID */
+
+ /* NOTE: this is an arbitrary random number that we use to count the
+ * number of unique OBS installations and is not associated with any
+ * kind of identifiable information */
+ const char *pguid = config_get_string(GetGlobalConfig(),
+ "General", "InstallGUID");
+ string guid;
+ if (pguid)
+ guid = pguid;
+
+ if (guid.empty()) {
+ GenerateGUID(guid);
+
+ if (!guid.empty())
+ config_set_string(GetGlobalConfig(),
+ "General", "InstallGUID",
+ guid.c_str());
+ }
+
+ if (!guid.empty()) {
+ string header = "X-OBS2-GUID: ";
+ header += guid;
+ extraHeaders.push_back(move(header));
+ }
+
+ /* ----------------------------------- *
+ * get manifest from server */
+
+ success = GetRemoteFile(WIN_MANIFEST_URL, text, error, &responseCode,
+ nullptr, nullptr, extraHeaders, &signature);
+
+ if (!success || (responseCode != 200 && responseCode != 304)) {
+ if (responseCode == 404)
+ return;
+
+ throw strprintf("Failed to fetch manifest file: %s", error);
+ }
+
+ /* ----------------------------------- *
+ * verify file signature */
+
+ /* a new file must be digitally signed */
+ if (responseCode == 200) {
+ success = CheckDataSignature(text, "manifest",
+ signature.data(), signature.size());
+ if (!success)
+ throw string("Invalid manifest signature");
+ }
+
+ /* ----------------------------------- *
+ * write or load manifest */
+
+ if (responseCode == 200) {
+ if (!QuickWriteFile(manifestPath, text.data(), text.size()))
+ throw strprintf("Could not write file '%s'",
+ manifestPath);
+ } else {
+ if (!QuickReadFile(manifestPath, text))
+ throw strprintf("Could not read file '%s'",
+ manifestPath);
+ }
+
+ /* ----------------------------------- *
+ * check manifest for update */
+
+ string notes;
+ int updateVer = 0;
+
+ success = ParseUpdateManifest(text.c_str(), &updatesAvailable, notes,
+ updateVer);
+ if (!success)
+ throw string("Failed to parse manifest");
+
+ if (!updatesAvailable) {
+ if (manualUpdate)
+ info(QTStr("Updater.NoUpdatesAvailable.Title"),
+ QTStr("Updater.NoUpdatesAvailable.Text"));
+ return;
+ }
+
+ /* ----------------------------------- *
+ * skip this version if set to skip */
+
+ int skipUpdateVer = config_get_int(GetGlobalConfig(), "General",
+ "SkipUpdateVersion");
+ if (!manualUpdate && updateVer == skipUpdateVer)
+ return;
+
+ /* ----------------------------------- *
+ * warn again if running or gc locked */
+
+ if (ActiveOrGameCaptureLocked())
+ return;
+
+ /* ----------------------------------- *
+ * fetch updater module */
+
+ if (!FetchUpdaterModule(WIN_UPDATER_URL))
+ return;
+
+ /* ----------------------------------- *
+ * query user for update */
+
+ int queryResult = queryUpdate(manualUpdate, notes.c_str());
+
+ if (queryResult == OBSUpdate::No) {
+ if (!manualUpdate) {
+ long long t = (long long)time(nullptr);
+ config_set_int(GetGlobalConfig(), "General",
+ "LastUpdateCheck", t);
+ }
+ return;
+
+ } else if (queryResult == OBSUpdate::Skip) {
+ config_set_int(GetGlobalConfig(), "General",
+ "SkipUpdateVersion", updateVer);
+ return;
+ }
+
+ /* ----------------------------------- *
+ * get working dir */
+
+ wchar_t cwd[MAX_PATH];
+ GetModuleFileNameW(nullptr, cwd, _countof(cwd) - 1);
+ wchar_t *p = wcsrchr(cwd, '\\');
+ if (p)
+ *p = 0;
+
+ /* ----------------------------------- *
+ * execute updater */
+
+ BPtr updateFilePath = GetConfigPathPtr(
+ "obs-studio\\updates\\updater.exe");
+ BPtr wUpdateFilePath;
+
+ size_t size = os_utf8_to_wcs_ptr(updateFilePath, 0, &wUpdateFilePath);
+ if (!size)
+ throw string("Could not convert updateFilePath to wide");
+
+ /* note, can't use CreateProcess to launch as admin. */
+ SHELLEXECUTEINFO execInfo = {};
+
+ execInfo.cbSize = sizeof(execInfo);
+ execInfo.lpFile = wUpdateFilePath;
+#ifndef UPDATE_CHANNEL
+#define UPDATE_ARG_SUFFIX L""
+#else
+#define UPDATE_ARG_SUFFIX UPDATE_CHANNEL
+#endif
+ if (App()->IsPortableMode())
+ execInfo.lpParameters = UPDATE_ARG_SUFFIX L" Portable";
+ else
+ execInfo.lpParameters = UPDATE_ARG_SUFFIX;
+
+ execInfo.lpDirectory = cwd;
+ execInfo.nShow = SW_SHOWNORMAL;
+
+ if (!ShellExecuteEx(&execInfo)) {
+ QString msg = QTStr("Updater.FailedToLaunch");
+ info(msg, msg);
+ throw strprintf("Can't launch updater '%s': %d",
+ updateFilePath, GetLastError());
+ }
+
+ /* force OBS to perform another update check immediately after updating
+ * in case of issues with the new version */
+ config_set_int(GetGlobalConfig(), "General", "LastUpdateCheck", 0);
+ config_set_int(GetGlobalConfig(), "General", "SkipUpdateVersion", 0);
+ config_set_string(GetGlobalConfig(), "General", "InstallGUID",
+ guid.c_str());
+
+ QMetaObject::invokeMethod(App()->GetMainWindow(), "close");
+
+} catch (string text) {
+ blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
+}
diff --git a/UI/win-update/win-update.hpp b/UI/win-update/win-update.hpp
new file mode 100644
index 0000000..47bdd03
--- /dev/null
+++ b/UI/win-update/win-update.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+#include
+
+class AutoUpdateThread : public QThread {
+ Q_OBJECT
+
+ bool manualUpdate;
+ bool user_confirmed = false;
+
+ virtual void run() override;
+
+ void info(const QString &title, const QString &text);
+ int queryUpdate(bool manualUpdate, const char *text_utf8);
+
+private slots:
+ void infoMsg(const QString &title, const QString &text);
+ int queryUpdateSlot(bool manualUpdate, const QString &text);
+
+public:
+ AutoUpdateThread(bool manualUpdate_) : manualUpdate(manualUpdate_) {}
+};
diff --git a/UI/window-basic-adv-audio.cpp b/UI/window-basic-adv-audio.cpp
index e983b51..ad3977d 100644
--- a/UI/window-basic-adv-audio.cpp
+++ b/UI/window-basic-adv-audio.cpp
@@ -22,26 +22,32 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
QWidget *widget;
QLabel *label;
+ int idx = 0;
mainLayout = new QGridLayout;
mainLayout->setContentsMargins(0, 0, 0, 0);
label = new QLabel(QTStr("Basic.AdvAudio.Name"));
label->setAlignment(Qt::AlignHCenter);
- mainLayout->addWidget(label, 0, 0);
+ mainLayout->addWidget(label, 0, idx++);
label = new QLabel(QTStr("Basic.AdvAudio.Volume"));
label->setAlignment(Qt::AlignHCenter);
- mainLayout->addWidget(label, 0, 1);
+ mainLayout->addWidget(label, 0, idx++);
label = new QLabel(QTStr("Basic.AdvAudio.Mono"));
label->setAlignment(Qt::AlignHCenter);
- mainLayout->addWidget(label, 0, 2);
+ mainLayout->addWidget(label, 0, idx++);
label = new QLabel(QTStr("Basic.AdvAudio.Panning"));
label->setAlignment(Qt::AlignHCenter);
- mainLayout->addWidget(label, 0, 3);
+ mainLayout->addWidget(label, 0, idx++);
label = new QLabel(QTStr("Basic.AdvAudio.SyncOffset"));
label->setAlignment(Qt::AlignHCenter);
- mainLayout->addWidget(label, 0, 4);
+ mainLayout->addWidget(label, 0, idx++);
+#if defined(_WIN32) || defined(__APPLE__)
+ label = new QLabel(QTStr("Basic.AdvAudio.Monitoring"));
+ label->setAlignment(Qt::AlignHCenter);
+ mainLayout->addWidget(label, 0, idx++);
+#endif
label = new QLabel(QTStr("Basic.AdvAudio.AudioTracks"));
label->setAlignment(Qt::AlignHCenter);
- mainLayout->addWidget(label, 0, 5);
+ mainLayout->addWidget(label, 0, idx++);
controlArea = new QWidget;
controlArea->setLayout(mainLayout);
diff --git a/UI/window-basic-filters.cpp b/UI/window-basic-filters.cpp
index f3bb847..f3d53e8 100644
--- a/UI/window-basic-filters.cpp
+++ b/UI/window-basic-filters.cpp
@@ -147,6 +147,7 @@ inline OBSSource OBSBasicFilters::GetFilter(int row, bool async)
void OBSBasicFilters::UpdatePropertiesView(int row, bool async)
{
if (view) {
+ ui->rightLayout->removeWidget(view);
view->deleteLater();
view = nullptr;
}
diff --git a/UI/window-basic-main-dropfiles.cpp b/UI/window-basic-main-dropfiles.cpp
index 64ae7f6..45475a6 100644
--- a/UI/window-basic-main-dropfiles.cpp
+++ b/UI/window-basic-main-dropfiles.cpp
@@ -11,6 +11,10 @@
using namespace std;
+static const char *textExtensions[] = {
+ "txt", "log", nullptr
+};
+
static const char *imageExtensions[] = {
"bmp", "tga", "png", "jpg", "jpeg", "gif", nullptr
};
@@ -52,19 +56,31 @@ static string GenerateSourceName(const char *base)
}
}
-void OBSBasic::AddDropSource(const char *file, bool image)
+void OBSBasic::AddDropSource(const char *data, DropType image)
{
OBSBasic *main = reinterpret_cast