Files
obs-studio/plugins/frontend-tools/output-timer.cpp
PatTheMav 1829492e6b cmake: Move frontend plugins into main plugins dir
Frontend plugins should not require being placed in the frontend
directory to be built successfully. Indeed they should only depend
on libobs and the obs-frontend-api and thus their source tree should
be able to exist anywhere (even standalone) and the plugin should still
compile successfully (just like any 3rd party plugin).

Thus moving those plugins into the main plugin directory ensures that
they don't require on any "special sauce" within the source tree to
compile.
2026-06-05 16:00:18 -04:00

320 lines
9.1 KiB
C++

#include <obs-frontend-api.h>
#include <obs-module.h>
#include <obs.hpp>
#include <util/util.hpp>
#include <QAction>
#include <QMainWindow>
#include <QTimer>
#include <QObject>
#include "output-timer.hpp"
using namespace std;
OutputTimer *ot;
OutputTimer::OutputTimer(QWidget *parent) : QDialog(parent), ui(new Ui_OutputTimer)
{
ui->setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
QObject::connect(ui->outputTimerStream, &QPushButton::clicked, this, &OutputTimer::StreamingTimerButton);
QObject::connect(ui->outputTimerRecord, &QPushButton::clicked, this, &OutputTimer::RecordingTimerButton);
QObject::connect(ui->buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this,
&OutputTimer::hide);
streamingTimer = new QTimer(this);
streamingTimerDisplay = new QTimer(this);
recordingTimer = new QTimer(this);
recordingTimerDisplay = new QTimer(this);
QObject::connect(streamingTimer, &QTimer::timeout, this, &OutputTimer::EventStopStreaming);
QObject::connect(streamingTimerDisplay, &QTimer::timeout, this, &OutputTimer::UpdateStreamTimerDisplay);
QObject::connect(recordingTimer, &QTimer::timeout, this, &OutputTimer::EventStopRecording);
QObject::connect(recordingTimerDisplay, &QTimer::timeout, this, &OutputTimer::UpdateRecordTimerDisplay);
}
void OutputTimer::closeEvent(QCloseEvent *)
{
obs_frontend_save();
}
void OutputTimer::StreamingTimerButton()
{
if (!obs_frontend_streaming_active()) {
blog(LOG_INFO, "Starting stream due to OutputTimer");
obs_frontend_streaming_start();
} else if (streamingAlreadyActive) {
StreamTimerStart();
streamingAlreadyActive = false;
} else if (obs_frontend_streaming_active()) {
blog(LOG_INFO, "Stopping stream due to OutputTimer");
obs_frontend_streaming_stop();
}
}
void OutputTimer::RecordingTimerButton()
{
if (!obs_frontend_recording_active()) {
blog(LOG_INFO, "Starting recording due to OutputTimer");
obs_frontend_recording_start();
} else if (recordingAlreadyActive) {
RecordTimerStart();
recordingAlreadyActive = false;
} else if (obs_frontend_recording_active()) {
blog(LOG_INFO, "Stopping recording due to OutputTimer");
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);
streamingTimer->start();
streamingTimerDisplay->start(1000);
ui->outputTimerStream->setText(obs_module_text("Stop"));
UpdateStreamTimerDisplay();
ui->outputTimerStream->setChecked(true);
}
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);
recordingTimer->start();
recordingTimerDisplay->start(1000);
ui->outputTimerRecord->setText(obs_module_text("Stop"));
UpdateRecordTimerDisplay();
ui->outputTimerRecord->setChecked(true);
}
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");
ui->outputTimerStream->setChecked(false);
}
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");
ui->outputTimerRecord->setChecked(false);
}
void OutputTimer::UpdateStreamTimerDisplay()
{
int remainingTime = streamingTimer->remainingTime() / 1000;
int seconds = remainingTime % 60;
int minutes = (remainingTime % 3600) / 60;
int hours = remainingTime / 3600;
QString text = QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds);
ui->streamTime->setText(text);
}
void OutputTimer::UpdateRecordTimerDisplay()
{
int remainingTime = 0;
if (obs_frontend_recording_paused() && ui->pauseRecordTimer->isChecked())
remainingTime = recordingTimeLeft / 1000;
else
remainingTime = recordingTimer->remainingTime() / 1000;
int seconds = remainingTime % 60;
int minutes = (remainingTime % 3600) / 60;
int hours = remainingTime / 3600;
QString text = QString::asprintf("%02d:%02d:%02d", hours, minutes, seconds);
ui->recordTime->setText(text);
}
void OutputTimer::PauseRecordingTimer()
{
if (!ui->pauseRecordTimer->isChecked())
return;
if (recordingTimer->isActive()) {
recordingTimeLeft = recordingTimer->remainingTime();
recordingTimer->stop();
}
}
void OutputTimer::UnpauseRecordingTimer()
{
if (!ui->pauseRecordTimer->isChecked())
return;
if (recordingTimeLeft > 0 && !recordingTimer->isActive())
recordingTimer->start(recordingTimeLeft);
}
void OutputTimer::ShowHideDialog()
{
if (!isVisible()) {
setVisible(true);
QTimer::singleShot(250, this, &OutputTimer::show);
} else {
setVisible(false);
QTimer::singleShot(250, this, &OutputTimer::hide);
}
}
void OutputTimer::EventStopStreaming()
{
blog(LOG_INFO, "Stopping stream due to OutputTimer timeout");
obs_frontend_streaming_stop();
}
void OutputTimer::EventStopRecording()
{
blog(LOG_INFO, "Stopping recording due to OutputTimer timeout");
obs_frontend_recording_stop();
}
static void SaveOutputTimer(obs_data_t *save_data, bool saving, void *)
{
if (saving) {
OBSDataAutoRelease 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_bool(obj, "pauseRecordTimer", ot->ui->pauseRecordTimer->isChecked());
obs_data_set_obj(save_data, "output-timer", obj);
} else {
OBSDataAutoRelease 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"));
ot->ui->pauseRecordTimer->setChecked(obs_data_get_bool(obj, "pauseRecordTimer"));
}
}
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();
} else if (event == OBS_FRONTEND_EVENT_RECORDING_PAUSED) {
ot->PauseRecordingTimer();
} else if (event == OBS_FRONTEND_EVENT_RECORDING_UNPAUSED) {
ot->UnpauseRecordingTimer();
}
}
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);
QObject::connect(action, &QAction::triggered, action, cb);
}