UI: Rewrite profile system to enable user-provided storage location
This change enables loading profiles from locations different than OBS' own configuration directory. It also rewrites profile management in the app to work off an in-memory collection of profiles found on disk and does not require iterating over directory contents for most profile interactions by the app.
This commit is contained in:
parent
2635cf3a2a
commit
607d37b423
@ -16,7 +16,6 @@ template<typename T> static T GetOBSRef(QListWidgetItem *item)
|
||||
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
|
||||
}
|
||||
|
||||
void EnumProfiles(function<bool(const char *, const char *)> &&cb);
|
||||
void EnumSceneCollections(function<bool(const char *, const char *)> &&cb);
|
||||
|
||||
extern volatile bool streaming_active;
|
||||
@ -218,29 +217,24 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
||||
void
|
||||
obs_frontend_get_profiles(std::vector<std::string> &strings) override
|
||||
{
|
||||
auto addProfile = [&](const char *name, const char *) {
|
||||
strings.emplace_back(name);
|
||||
return true;
|
||||
};
|
||||
const OBSProfileCache &profiles = main->GetProfileCache();
|
||||
|
||||
EnumProfiles(addProfile);
|
||||
for (auto &[profileName, profile] : profiles) {
|
||||
strings.emplace_back(profileName);
|
||||
}
|
||||
}
|
||||
|
||||
char *obs_frontend_get_current_profile(void) override
|
||||
{
|
||||
const char *name = config_get_string(App()->GlobalConfig(),
|
||||
"Basic", "Profile");
|
||||
return bstrdup(name);
|
||||
const OBSProfile &profile = main->GetCurrentProfile();
|
||||
return bstrdup(profile.name.c_str());
|
||||
}
|
||||
|
||||
char *obs_frontend_get_current_profile_path(void) override
|
||||
{
|
||||
char profilePath[512];
|
||||
int ret = GetProfilePath(profilePath, sizeof(profilePath), "");
|
||||
if (ret <= 0)
|
||||
return nullptr;
|
||||
const OBSProfile &profile = main->GetCurrentProfile();
|
||||
|
||||
return bstrdup(profilePath);
|
||||
return bstrdup(profile.path.u8string().c_str());
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_profile(const char *profile) override
|
||||
@ -510,353 +504,323 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
||||
|
||||
config_t *obs_frontend_get_profile_config(void) override
|
||||
{
|
||||
return main->basicConfig;
|
||||
config_t *obs_frontend_get_global_config(void) override
|
||||
{
|
||||
blog(LOG_WARNING,
|
||||
"DEPRECATION: obs_frontend_get_global_config is deprecated. Read from global or user configuration explicitly instead.");
|
||||
return App()->GetAppConfig();
|
||||
}
|
||||
|
||||
config_t *obs_frontend_get_app_config(void) override
|
||||
{
|
||||
return App()->GetAppConfig();
|
||||
}
|
||||
|
||||
config_t *obs_frontend_get_user_config(void) override
|
||||
{
|
||||
return App()->GetUserConfig();
|
||||
}
|
||||
|
||||
void obs_frontend_open_projector(const char *type, int monitor,
|
||||
const char *geometry,
|
||||
const char *name) override
|
||||
{
|
||||
SavedProjectorInfo proj = {
|
||||
ProjectorType::Preview,
|
||||
monitor,
|
||||
geometry ? geometry : "",
|
||||
name ? name : "",
|
||||
};
|
||||
if (type) {
|
||||
if (astrcmpi(type, "Source") == 0)
|
||||
proj.type = ProjectorType::Source;
|
||||
else if (astrcmpi(type, "Scene") == 0)
|
||||
proj.type = ProjectorType::Scene;
|
||||
else if (astrcmpi(type, "StudioProgram") == 0)
|
||||
proj.type =
|
||||
ProjectorType::StudioProgram;
|
||||
else if (astrcmpi(type, "Multiview") == 0)
|
||||
proj.type = ProjectorType::Multiview;
|
||||
}
|
||||
QMetaObject::invokeMethod(
|
||||
main, "OpenSavedProjector", WaitConnection(),
|
||||
Q_ARG(SavedProjectorInfo *, &proj));
|
||||
}
|
||||
|
||||
void obs_frontend_save(void) override
|
||||
{
|
||||
main->SaveProject();
|
||||
}
|
||||
|
||||
void obs_frontend_defer_save_begin(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "DeferSaveBegin");
|
||||
}
|
||||
|
||||
void obs_frontend_defer_save_end(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "DeferSaveEnd");
|
||||
}
|
||||
|
||||
void obs_frontend_add_save_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)
|
||||
override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(saveCallbacks, callback,
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
saveCallbacks.emplace_back(callback,
|
||||
private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_save_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)
|
||||
override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(saveCallbacks, callback,
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
return;
|
||||
|
||||
saveCallbacks.erase(saveCallbacks.begin() + idx);
|
||||
}
|
||||
|
||||
void obs_frontend_add_preload_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)
|
||||
override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(preloadCallbacks, callback,
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
preloadCallbacks.emplace_back(callback,
|
||||
private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_preload_callback(
|
||||
obs_frontend_save_cb callback, void *private_data)
|
||||
override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(preloadCallbacks, callback,
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
return;
|
||||
|
||||
preloadCallbacks.erase(preloadCallbacks.begin() + idx);
|
||||
}
|
||||
|
||||
void obs_frontend_push_ui_translation(
|
||||
obs_frontend_translate_ui_cb translate) override
|
||||
{
|
||||
App()->PushUITranslation(translate);
|
||||
}
|
||||
|
||||
void obs_frontend_pop_ui_translation(void) override
|
||||
{
|
||||
App()->PopUITranslation();
|
||||
}
|
||||
|
||||
void obs_frontend_set_streaming_service(obs_service_t * service)
|
||||
override
|
||||
{
|
||||
main->SetService(service);
|
||||
}
|
||||
|
||||
obs_service_t *obs_frontend_get_streaming_service(void) override
|
||||
{
|
||||
return main->GetService();
|
||||
}
|
||||
|
||||
void obs_frontend_save_streaming_service(void) override
|
||||
{
|
||||
main->SaveService();
|
||||
}
|
||||
|
||||
bool obs_frontend_preview_program_mode_active(void) override
|
||||
{
|
||||
return main->IsPreviewProgramMode();
|
||||
}
|
||||
|
||||
void obs_frontend_set_preview_program_mode(bool enable) override
|
||||
{
|
||||
main->SetPreviewProgramMode(enable);
|
||||
}
|
||||
|
||||
void obs_frontend_preview_program_trigger_transition(void)
|
||||
override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "TransitionClicked");
|
||||
}
|
||||
|
||||
bool obs_frontend_preview_enabled(void) override
|
||||
{
|
||||
return main->previewEnabled;
|
||||
}
|
||||
|
||||
void obs_frontend_set_preview_enabled(bool enable) override
|
||||
{
|
||||
if (main->previewEnabled != enable)
|
||||
main->EnablePreviewDisplay(enable);
|
||||
}
|
||||
|
||||
obs_source_t *obs_frontend_get_current_preview_scene(void)
|
||||
override
|
||||
{
|
||||
if (main->IsPreviewProgramMode()) {
|
||||
OBSSource source =
|
||||
main->GetCurrentSceneSource();
|
||||
return obs_source_get_ref(source);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void obs_frontend_set_current_preview_scene(obs_source_t *
|
||||
scene) override
|
||||
{
|
||||
if (main->IsPreviewProgramMode()) {
|
||||
QMetaObject::invokeMethod(
|
||||
main, "SetCurrentScene",
|
||||
Q_ARG(OBSSource, OBSSource(scene)),
|
||||
Q_ARG(bool, false));
|
||||
}
|
||||
}
|
||||
|
||||
void obs_frontend_take_screenshot(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "Screenshot");
|
||||
}
|
||||
|
||||
void obs_frontend_take_source_screenshot(obs_source_t * source)
|
||||
override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "Screenshot",
|
||||
Q_ARG(OBSSource,
|
||||
OBSSource(source)));
|
||||
}
|
||||
|
||||
obs_output_t *obs_frontend_get_virtualcam_output(void) override
|
||||
{
|
||||
OBSOutput output =
|
||||
main->outputHandler->virtualCam.Get();
|
||||
return obs_output_get_ref(output);
|
||||
}
|
||||
|
||||
void obs_frontend_start_virtualcam(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "StartVirtualCam");
|
||||
}
|
||||
|
||||
void obs_frontend_stop_virtualcam(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "StopVirtualCam");
|
||||
}
|
||||
|
||||
bool obs_frontend_virtualcam_active(void) override
|
||||
{
|
||||
return os_atomic_load_bool(&virtualcam_active);
|
||||
}
|
||||
|
||||
void obs_frontend_reset_video(void) override
|
||||
{
|
||||
main->ResetVideo();
|
||||
}
|
||||
|
||||
void obs_frontend_open_source_properties(obs_source_t * source)
|
||||
override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenProperties",
|
||||
Q_ARG(OBSSource,
|
||||
OBSSource(source)));
|
||||
}
|
||||
|
||||
void obs_frontend_open_source_filters(obs_source_t * source)
|
||||
override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenFilters",
|
||||
Q_ARG(OBSSource,
|
||||
OBSSource(source)));
|
||||
}
|
||||
|
||||
void obs_frontend_open_source_interaction(obs_source_t * source)
|
||||
override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenInteraction",
|
||||
Q_ARG(OBSSource,
|
||||
OBSSource(source)));
|
||||
}
|
||||
|
||||
void obs_frontend_open_sceneitem_edit_transform(
|
||||
obs_sceneitem_t * item) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenEditTransform",
|
||||
Q_ARG(OBSSceneItem,
|
||||
OBSSceneItem(item)));
|
||||
}
|
||||
|
||||
char *obs_frontend_get_current_record_output_path(void) override
|
||||
{
|
||||
const char *recordOutputPath =
|
||||
main->GetCurrentOutputPath();
|
||||
|
||||
return bstrdup(recordOutputPath);
|
||||
}
|
||||
|
||||
const char *obs_frontend_get_locale_string(const char *string)
|
||||
override
|
||||
{
|
||||
return Str(string);
|
||||
}
|
||||
|
||||
bool obs_frontend_is_theme_dark(void) override
|
||||
{
|
||||
return App()->IsThemeDark();
|
||||
}
|
||||
|
||||
char *obs_frontend_get_last_recording(void) override
|
||||
{
|
||||
return bstrdup(
|
||||
main->outputHandler->lastRecordingPath.c_str());
|
||||
}
|
||||
|
||||
char *obs_frontend_get_last_screenshot(void) override
|
||||
{
|
||||
return bstrdup(main->lastScreenshot.c_str());
|
||||
}
|
||||
|
||||
char *obs_frontend_get_last_replay(void) override
|
||||
{
|
||||
return bstrdup(main->lastReplay.c_str());
|
||||
}
|
||||
|
||||
void obs_frontend_add_undo_redo_action(
|
||||
const char *name, const undo_redo_cb undo,
|
||||
const undo_redo_cb redo, const char *undo_data,
|
||||
const char *redo_data, bool repeatable) override
|
||||
{
|
||||
main->undo_s.add_action(
|
||||
name,
|
||||
[undo](const std::string &data) {
|
||||
undo(data.c_str());
|
||||
},
|
||||
[redo](const std::string &data) {
|
||||
redo(data.c_str());
|
||||
},
|
||||
undo_data, redo_data, repeatable);
|
||||
}
|
||||
|
||||
void on_load(obs_data_t * settings) override
|
||||
{
|
||||
for (size_t i = saveCallbacks.size(); i > 0; i--) {
|
||||
auto cb = saveCallbacks[i - 1];
|
||||
cb.callback(settings, false, cb.private_data);
|
||||
}
|
||||
}
|
||||
|
||||
void on_preload(obs_data_t * settings) override
|
||||
{
|
||||
for (size_t i = preloadCallbacks.size(); i > 0; i--) {
|
||||
auto cb = preloadCallbacks[i - 1];
|
||||
cb.callback(settings, false, cb.private_data);
|
||||
}
|
||||
}
|
||||
|
||||
void on_save(obs_data_t * settings) override
|
||||
{
|
||||
for (size_t i = saveCallbacks.size(); i > 0; i--) {
|
||||
auto cb = saveCallbacks[i - 1];
|
||||
cb.callback(settings, true, cb.private_data);
|
||||
}
|
||||
}
|
||||
|
||||
void on_event(enum obs_frontend_event event) override
|
||||
{
|
||||
if (main->disableSaving &&
|
||||
event !=
|
||||
OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP &&
|
||||
event != OBS_FRONTEND_EVENT_EXIT)
|
||||
return;
|
||||
|
||||
for (size_t i = callbacks.size(); i > 0; i--) {
|
||||
auto cb = callbacks[i - 1];
|
||||
cb.callback(event, cb.private_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main)
|
||||
{
|
||||
obs_frontend_callbacks *api = new OBSStudioAPI(main);
|
||||
obs_frontend_set_callbacks_internal(api);
|
||||
return api;
|
||||
return main->activeConfiguration;
|
||||
}
|
||||
|
||||
config_t *obs_frontend_get_global_config(void) override
|
||||
{
|
||||
blog(LOG_WARNING,
|
||||
"DEPRECATION: obs_frontend_get_global_config is deprecated. Read from global or user configuration explicitly instead.");
|
||||
return App()->GetAppConfig();
|
||||
}
|
||||
|
||||
config_t *obs_frontend_get_app_config(void) override
|
||||
{
|
||||
return App()->GetAppConfig();
|
||||
}
|
||||
|
||||
config_t *obs_frontend_get_user_config(void) override
|
||||
{
|
||||
return App()->GetUserConfig();
|
||||
}
|
||||
|
||||
void obs_frontend_open_projector(const char *type, int monitor,
|
||||
const char *geometry,
|
||||
const char *name) override
|
||||
{
|
||||
SavedProjectorInfo proj = {
|
||||
ProjectorType::Preview,
|
||||
monitor,
|
||||
geometry ? geometry : "",
|
||||
name ? name : "",
|
||||
};
|
||||
if (type) {
|
||||
if (astrcmpi(type, "Source") == 0)
|
||||
proj.type = ProjectorType::Source;
|
||||
else if (astrcmpi(type, "Scene") == 0)
|
||||
proj.type = ProjectorType::Scene;
|
||||
else if (astrcmpi(type, "StudioProgram") == 0)
|
||||
proj.type = ProjectorType::StudioProgram;
|
||||
else if (astrcmpi(type, "Multiview") == 0)
|
||||
proj.type = ProjectorType::Multiview;
|
||||
}
|
||||
QMetaObject::invokeMethod(main, "OpenSavedProjector",
|
||||
WaitConnection(),
|
||||
Q_ARG(SavedProjectorInfo *, &proj));
|
||||
}
|
||||
|
||||
void obs_frontend_save(void) override { main->SaveProject(); }
|
||||
|
||||
void obs_frontend_defer_save_begin(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "DeferSaveBegin");
|
||||
}
|
||||
|
||||
void obs_frontend_defer_save_end(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "DeferSaveEnd");
|
||||
}
|
||||
|
||||
void obs_frontend_add_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx =
|
||||
GetCallbackIdx(saveCallbacks, callback, private_data);
|
||||
if (idx == (size_t)-1)
|
||||
saveCallbacks.emplace_back(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_save_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx =
|
||||
GetCallbackIdx(saveCallbacks, callback, private_data);
|
||||
if (idx == (size_t)-1)
|
||||
return;
|
||||
|
||||
saveCallbacks.erase(saveCallbacks.begin() + idx);
|
||||
}
|
||||
|
||||
void obs_frontend_add_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(preloadCallbacks, callback,
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
preloadCallbacks.emplace_back(callback, private_data);
|
||||
}
|
||||
|
||||
void obs_frontend_remove_preload_callback(obs_frontend_save_cb callback,
|
||||
void *private_data) override
|
||||
{
|
||||
size_t idx = GetCallbackIdx(preloadCallbacks, callback,
|
||||
private_data);
|
||||
if (idx == (size_t)-1)
|
||||
return;
|
||||
|
||||
preloadCallbacks.erase(preloadCallbacks.begin() + idx);
|
||||
}
|
||||
|
||||
void obs_frontend_push_ui_translation(
|
||||
obs_frontend_translate_ui_cb translate) override
|
||||
{
|
||||
App()->PushUITranslation(translate);
|
||||
}
|
||||
|
||||
void obs_frontend_pop_ui_translation(void) override
|
||||
{
|
||||
App()->PopUITranslation();
|
||||
}
|
||||
|
||||
void obs_frontend_set_streaming_service(obs_service_t *service) override
|
||||
{
|
||||
main->SetService(service);
|
||||
}
|
||||
|
||||
obs_service_t *obs_frontend_get_streaming_service(void) override
|
||||
{
|
||||
return main->GetService();
|
||||
}
|
||||
|
||||
void obs_frontend_save_streaming_service(void) override
|
||||
{
|
||||
main->SaveService();
|
||||
}
|
||||
|
||||
bool obs_frontend_preview_program_mode_active(void) override
|
||||
{
|
||||
return main->IsPreviewProgramMode();
|
||||
}
|
||||
|
||||
void obs_frontend_set_preview_program_mode(bool enable) override
|
||||
{
|
||||
main->SetPreviewProgramMode(enable);
|
||||
}
|
||||
|
||||
void obs_frontend_preview_program_trigger_transition(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "TransitionClicked");
|
||||
}
|
||||
|
||||
bool obs_frontend_preview_enabled(void) override
|
||||
{
|
||||
return main->previewEnabled;
|
||||
}
|
||||
|
||||
void obs_frontend_set_preview_enabled(bool enable) override
|
||||
{
|
||||
if (main->previewEnabled != enable)
|
||||
main->EnablePreviewDisplay(enable);
|
||||
}
|
||||
|
||||
obs_source_t *obs_frontend_get_current_preview_scene(void) override
|
||||
{
|
||||
if (main->IsPreviewProgramMode()) {
|
||||
OBSSource source = main->GetCurrentSceneSource();
|
||||
return obs_source_get_ref(source);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
obs_frontend_set_current_preview_scene(obs_source_t *scene) override
|
||||
{
|
||||
if (main->IsPreviewProgramMode()) {
|
||||
QMetaObject::invokeMethod(main, "SetCurrentScene",
|
||||
Q_ARG(OBSSource,
|
||||
OBSSource(scene)),
|
||||
Q_ARG(bool, false));
|
||||
}
|
||||
}
|
||||
|
||||
void obs_frontend_take_screenshot(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "Screenshot");
|
||||
}
|
||||
|
||||
void obs_frontend_take_source_screenshot(obs_source_t *source) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "Screenshot",
|
||||
Q_ARG(OBSSource, OBSSource(source)));
|
||||
}
|
||||
|
||||
obs_output_t *obs_frontend_get_virtualcam_output(void) override
|
||||
{
|
||||
OBSOutput output = main->outputHandler->virtualCam.Get();
|
||||
return obs_output_get_ref(output);
|
||||
}
|
||||
|
||||
void obs_frontend_start_virtualcam(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "StartVirtualCam");
|
||||
}
|
||||
|
||||
void obs_frontend_stop_virtualcam(void) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "StopVirtualCam");
|
||||
}
|
||||
|
||||
bool obs_frontend_virtualcam_active(void) override
|
||||
{
|
||||
return os_atomic_load_bool(&virtualcam_active);
|
||||
}
|
||||
|
||||
void obs_frontend_reset_video(void) override { main->ResetVideo(); }
|
||||
|
||||
void obs_frontend_open_source_properties(obs_source_t *source) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenProperties",
|
||||
Q_ARG(OBSSource, OBSSource(source)));
|
||||
}
|
||||
|
||||
void obs_frontend_open_source_filters(obs_source_t *source) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenFilters",
|
||||
Q_ARG(OBSSource, OBSSource(source)));
|
||||
}
|
||||
|
||||
void obs_frontend_open_source_interaction(obs_source_t *source) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenInteraction",
|
||||
Q_ARG(OBSSource, OBSSource(source)));
|
||||
}
|
||||
|
||||
void obs_frontend_open_sceneitem_edit_transform(
|
||||
obs_sceneitem_t *item) override
|
||||
{
|
||||
QMetaObject::invokeMethod(main, "OpenEditTransform",
|
||||
Q_ARG(OBSSceneItem,
|
||||
OBSSceneItem(item)));
|
||||
}
|
||||
|
||||
char *obs_frontend_get_current_record_output_path(void) override
|
||||
{
|
||||
const char *recordOutputPath = main->GetCurrentOutputPath();
|
||||
|
||||
return bstrdup(recordOutputPath);
|
||||
}
|
||||
|
||||
const char *obs_frontend_get_locale_string(const char *string) override
|
||||
{
|
||||
return Str(string);
|
||||
}
|
||||
|
||||
bool obs_frontend_is_theme_dark(void) override
|
||||
{
|
||||
return App()->IsThemeDark();
|
||||
}
|
||||
|
||||
char *obs_frontend_get_last_recording(void) override
|
||||
{
|
||||
return bstrdup(main->outputHandler->lastRecordingPath.c_str());
|
||||
}
|
||||
|
||||
char *obs_frontend_get_last_screenshot(void) override
|
||||
{
|
||||
return bstrdup(main->lastScreenshot.c_str());
|
||||
}
|
||||
|
||||
char *obs_frontend_get_last_replay(void) override
|
||||
{
|
||||
return bstrdup(main->lastReplay.c_str());
|
||||
}
|
||||
|
||||
void obs_frontend_add_undo_redo_action(const char *name,
|
||||
const undo_redo_cb undo,
|
||||
const undo_redo_cb redo,
|
||||
const char *undo_data,
|
||||
const char *redo_data,
|
||||
bool repeatable) override
|
||||
{
|
||||
main->undo_s.add_action(
|
||||
name,
|
||||
[undo](const std::string &data) { undo(data.c_str()); },
|
||||
[redo](const std::string &data) { redo(data.c_str()); },
|
||||
undo_data, redo_data, repeatable);
|
||||
}
|
||||
|
||||
void on_load(obs_data_t *settings) override
|
||||
{
|
||||
for (size_t i = saveCallbacks.size(); i > 0; i--) {
|
||||
auto cb = saveCallbacks[i - 1];
|
||||
cb.callback(settings, false, cb.private_data);
|
||||
}
|
||||
}
|
||||
|
||||
void on_preload(obs_data_t *settings) override
|
||||
{
|
||||
for (size_t i = preloadCallbacks.size(); i > 0; i--) {
|
||||
auto cb = preloadCallbacks[i - 1];
|
||||
cb.callback(settings, false, cb.private_data);
|
||||
}
|
||||
}
|
||||
|
||||
void on_save(obs_data_t *settings) override
|
||||
{
|
||||
for (size_t i = saveCallbacks.size(); i > 0; i--) {
|
||||
auto cb = saveCallbacks[i - 1];
|
||||
cb.callback(settings, true, cb.private_data);
|
||||
}
|
||||
}
|
||||
|
||||
void on_event(enum obs_frontend_event event) override
|
||||
{
|
||||
if (main->disableSaving &&
|
||||
event != OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP &&
|
||||
event != OBS_FRONTEND_EVENT_EXIT)
|
||||
return;
|
||||
|
||||
for (size_t i = callbacks.size(); i > 0; i--) {
|
||||
auto cb = callbacks[i - 1];
|
||||
cb.callback(event, cb.private_data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main)
|
||||
{
|
||||
obs_frontend_callbacks *api = new OBSStudioAPI(main);
|
||||
obs_frontend_set_callbacks_internal(api);
|
||||
return api;
|
||||
}
|
||||
|
239
UI/obs-app.cpp
239
UI/obs-app.cpp
@ -609,111 +609,43 @@ static bool MakeUserDirs()
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr std::string_view OBSProfileSubDirectory = "obs-studio/basic/profiles";
|
||||
constexpr std::string_view OBSScenesSubDirectory = "obs-studio/basic/scenes";
|
||||
|
||||
static bool MakeUserProfileDirs()
|
||||
{
|
||||
char path[512];
|
||||
const std::filesystem::path userProfilePath =
|
||||
App()->userProfilesLocation /
|
||||
std::filesystem::u8path(OBSProfileSubDirectory);
|
||||
const std::filesystem::path userScenesPath =
|
||||
App()->userScenesLocation /
|
||||
std::filesystem::u8path(OBSScenesSubDirectory);
|
||||
|
||||
if (GetConfigPath(path, sizeof(path), "obs-studio/basic/profiles") <= 0)
|
||||
return false;
|
||||
if (!do_mkdir(path))
|
||||
return false;
|
||||
if (!std::filesystem::exists(userProfilePath)) {
|
||||
try {
|
||||
std::filesystem::create_directories(userProfilePath);
|
||||
} catch (const std::filesystem::filesystem_error &error) {
|
||||
blog(LOG_ERROR,
|
||||
"Failed to create user profile directory '%s'\n%s",
|
||||
userProfilePath.u8string().c_str(), error.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes") <= 0)
|
||||
return false;
|
||||
if (!do_mkdir(path))
|
||||
return false;
|
||||
if (!std::filesystem::exists(userScenesPath)) {
|
||||
try {
|
||||
std::filesystem::create_directories(userScenesPath);
|
||||
} catch (const std::filesystem::filesystem_error &error) {
|
||||
blog(LOG_ERROR,
|
||||
"Failed to create user scene collection directory '%s'\n%s",
|
||||
userScenesPath.u8string().c_str(), error.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static string GetProfileDirFromName(const char *name)
|
||||
{
|
||||
string outputPath;
|
||||
os_glob_t *glob;
|
||||
char path[512];
|
||||
|
||||
if (GetConfigPath(path, sizeof(path), "obs-studio/basic/profiles") <= 0)
|
||||
return outputPath;
|
||||
|
||||
strcat(path, "/*");
|
||||
|
||||
if (os_glob(path, 0, &glob) != 0)
|
||||
return outputPath;
|
||||
|
||||
for (size_t i = 0; i < glob->gl_pathc; i++) {
|
||||
struct os_globent ent = glob->gl_pathv[i];
|
||||
if (!ent.directory)
|
||||
continue;
|
||||
|
||||
strcpy(path, ent.path);
|
||||
strcat(path, "/basic.ini");
|
||||
|
||||
ConfigFile config;
|
||||
if (config.Open(path, CONFIG_OPEN_EXISTING) != 0)
|
||||
continue;
|
||||
|
||||
const char *curName =
|
||||
config_get_string(config, "General", "Name");
|
||||
if (astrcmpi(curName, name) == 0) {
|
||||
outputPath = ent.path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
os_globfree(glob);
|
||||
|
||||
if (!outputPath.empty()) {
|
||||
replace(outputPath.begin(), outputPath.end(), '\\', '/');
|
||||
const char *start = strrchr(outputPath.c_str(), '/');
|
||||
if (start)
|
||||
outputPath.erase(0, start - outputPath.c_str() + 1);
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
static string GetSceneCollectionFileFromName(const char *name)
|
||||
{
|
||||
string outputPath;
|
||||
os_glob_t *glob;
|
||||
char path[512];
|
||||
|
||||
if (GetConfigPath(path, sizeof(path), "obs-studio/basic/scenes") <= 0)
|
||||
return outputPath;
|
||||
|
||||
strcat(path, "/*.json");
|
||||
|
||||
if (os_glob(path, 0, &glob) != 0)
|
||||
return outputPath;
|
||||
|
||||
for (size_t i = 0; i < glob->gl_pathc; i++) {
|
||||
struct os_globent ent = glob->gl_pathv[i];
|
||||
if (ent.directory)
|
||||
continue;
|
||||
|
||||
OBSDataAutoRelease data =
|
||||
obs_data_create_from_json_file_safe(ent.path, "bak");
|
||||
const char *curName = obs_data_get_string(data, "name");
|
||||
|
||||
if (astrcmpi(name, curName) == 0) {
|
||||
outputPath = ent.path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
os_globfree(glob);
|
||||
|
||||
if (!outputPath.empty()) {
|
||||
outputPath.resize(outputPath.size() - 5);
|
||||
replace(outputPath.begin(), outputPath.end(), '\\', '/');
|
||||
const char *start = strrchr(outputPath.c_str(), '/');
|
||||
if (start)
|
||||
outputPath.erase(0, start - outputPath.c_str() + 1);
|
||||
}
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
bool OBSApp::UpdatePre22MultiviewLayout(const char *layout)
|
||||
{
|
||||
if (!layout)
|
||||
@ -1212,56 +1144,77 @@ OBSApp::~OBSApp()
|
||||
static void move_basic_to_profiles(void)
|
||||
{
|
||||
char path[512];
|
||||
char new_path[512];
|
||||
os_glob_t *glob;
|
||||
|
||||
/* if not first time use */
|
||||
if (GetConfigPath(path, 512, "obs-studio/basic") <= 0)
|
||||
if (GetAppConfigPath(path, 512, "obs-studio/basic") <= 0) {
|
||||
return;
|
||||
if (!os_file_exists(path))
|
||||
return;
|
||||
|
||||
/* if the profiles directory doesn't already exist */
|
||||
if (GetConfigPath(new_path, 512, "obs-studio/basic/profiles") <= 0)
|
||||
return;
|
||||
if (os_file_exists(new_path))
|
||||
return;
|
||||
|
||||
if (os_mkdir(new_path) == MKDIR_ERROR)
|
||||
return;
|
||||
|
||||
strcat(new_path, "/");
|
||||
strcat(new_path, Str("Untitled"));
|
||||
if (os_mkdir(new_path) == MKDIR_ERROR)
|
||||
return;
|
||||
|
||||
strcat(path, "/*.*");
|
||||
if (os_glob(path, 0, &glob) != 0)
|
||||
return;
|
||||
|
||||
strcpy(path, new_path);
|
||||
|
||||
for (size_t i = 0; i < glob->gl_pathc; i++) {
|
||||
struct os_globent ent = glob->gl_pathv[i];
|
||||
char *file;
|
||||
|
||||
if (ent.directory)
|
||||
continue;
|
||||
|
||||
file = strrchr(ent.path, '/');
|
||||
if (!file++)
|
||||
continue;
|
||||
|
||||
if (astrcmpi(file, "scenes.json") == 0)
|
||||
continue;
|
||||
|
||||
strcpy(new_path, path);
|
||||
strcat(new_path, "/");
|
||||
strcat(new_path, file);
|
||||
os_rename(ent.path, new_path);
|
||||
}
|
||||
|
||||
os_globfree(glob);
|
||||
const std::filesystem::path basicPath = std::filesystem::u8path(path);
|
||||
|
||||
if (!std::filesystem::exists(basicPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::filesystem::path profilesPath =
|
||||
App()->userProfilesLocation /
|
||||
std::filesystem::u8path("obs-studio/basic/profiles");
|
||||
|
||||
if (std::filesystem::exists(profilesPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
std::filesystem::create_directories(profilesPath);
|
||||
} catch (const std::filesystem::filesystem_error &error) {
|
||||
blog(LOG_ERROR,
|
||||
"Failed to create profiles directory for migration from basic profile\n%s",
|
||||
error.what());
|
||||
return;
|
||||
}
|
||||
|
||||
const std::filesystem::path newProfilePath =
|
||||
profilesPath / std::filesystem::u8path(Str("Untitled"));
|
||||
|
||||
for (auto &entry : std::filesystem::directory_iterator(basicPath)) {
|
||||
if (entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.path().filename().u8string() == "scenes.json") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(newProfilePath)) {
|
||||
try {
|
||||
std::filesystem::create_directory(
|
||||
newProfilePath);
|
||||
} catch (
|
||||
const std::filesystem::filesystem_error &error) {
|
||||
blog(LOG_ERROR,
|
||||
"Failed to create profile directory for 'Untitled'\n%s",
|
||||
error.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const filesystem::path destinationFile =
|
||||
newProfilePath / entry.path().filename();
|
||||
|
||||
const auto copyOptions =
|
||||
std::filesystem::copy_options::overwrite_existing;
|
||||
|
||||
try {
|
||||
std::filesystem::copy(entry.path(), destinationFile,
|
||||
copyOptions);
|
||||
} catch (const std::filesystem::filesystem_error &error) {
|
||||
blog(LOG_ERROR,
|
||||
"Failed to copy basic profile file '%s' to new profile 'Untitled'\n%s",
|
||||
entry.path().filename().u8string().c_str(),
|
||||
error.what());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void move_basic_to_scene_collections(void)
|
||||
|
@ -39,18 +39,24 @@ extern QCefCookieManager *panel_cookies;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define SERVICE_PATH "service.json"
|
||||
constexpr std::string_view OBSServiceFileName = "service.json";
|
||||
|
||||
static OBSData OpenServiceSettings(std::string &type)
|
||||
{
|
||||
char serviceJsonPath[512];
|
||||
int ret = GetProfilePath(serviceJsonPath, sizeof(serviceJsonPath),
|
||||
SERVICE_PATH);
|
||||
if (ret <= 0)
|
||||
return OBSData();
|
||||
const OBSBasic *basic =
|
||||
reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
const OBSProfile ¤tProfile = basic->GetCurrentProfile();
|
||||
|
||||
OBSDataAutoRelease data =
|
||||
obs_data_create_from_json_file_safe(serviceJsonPath, "bak");
|
||||
const std::filesystem::path jsonFilePath =
|
||||
currentProfile.path /
|
||||
std::filesystem::u8path(OBSServiceFileName);
|
||||
|
||||
if (!std::filesystem::exists(jsonFilePath)) {
|
||||
return OBSData();
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data = obs_data_create_from_json_file_safe(
|
||||
jsonFilePath.u8string().c_str(), "bak");
|
||||
|
||||
obs_data_set_default_string(data, "type", "rtmp_common");
|
||||
type = obs_data_get_string(data, "type");
|
||||
|
@ -1616,19 +1616,28 @@ struct AdvancedOutput : BasicOutputHandler {
|
||||
|
||||
static OBSData GetDataFromJsonFile(const char *jsonFile)
|
||||
{
|
||||
char fullPath[512];
|
||||
const OBSBasic *basic =
|
||||
reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
|
||||
const OBSProfile ¤tProfile = basic->GetCurrentProfile();
|
||||
|
||||
const std::filesystem::path jsonFilePath =
|
||||
currentProfile.path / std::filesystem::u8path(jsonFile);
|
||||
|
||||
OBSDataAutoRelease data = nullptr;
|
||||
|
||||
int ret = GetProfilePath(fullPath, sizeof(fullPath), jsonFile);
|
||||
if (ret > 0) {
|
||||
BPtr<char> jsonData = os_quick_read_utf8_file(fullPath);
|
||||
if (!jsonFilePath.empty()) {
|
||||
BPtr<char> jsonData = os_quick_read_utf8_file(
|
||||
jsonFilePath.u8string().c_str());
|
||||
|
||||
if (!!jsonData) {
|
||||
data = obs_data_create_from_json(jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!data)
|
||||
if (!data) {
|
||||
data = obs_data_create();
|
||||
}
|
||||
|
||||
return data.Get();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -134,6 +134,37 @@ private:
|
||||
std::shared_ptr<OBSSignal> renamedSignal;
|
||||
};
|
||||
|
||||
struct OBSProfile {
|
||||
std::string name;
|
||||
std::string directoryName;
|
||||
std::filesystem::path path;
|
||||
std::filesystem::path profileFile;
|
||||
};
|
||||
|
||||
struct OBSSceneCollection {
|
||||
std::string name;
|
||||
std::string fileName;
|
||||
std::filesystem::path collectionFile;
|
||||
};
|
||||
|
||||
struct OBSPromptResult {
|
||||
bool success;
|
||||
std::string promptValue;
|
||||
bool optionValue;
|
||||
};
|
||||
|
||||
struct OBSPromptRequest {
|
||||
std::string title;
|
||||
std::string prompt;
|
||||
std::string promptValue;
|
||||
bool withOption;
|
||||
std::string optionPrompt;
|
||||
bool optionValue;
|
||||
};
|
||||
|
||||
using OBSPromptCallback = std::function<bool(const OBSPromptResult &result)>;
|
||||
|
||||
using OBSProfileCache = std::map<std::string, OBSProfile>;
|
||||
class ColorSelect : public QWidget {
|
||||
|
||||
public:
|
||||
@ -443,17 +474,6 @@ private:
|
||||
void RefreshSceneCollections();
|
||||
void ChangeSceneCollection();
|
||||
void LogScenes();
|
||||
|
||||
void ResetProfileData();
|
||||
bool AddProfile(bool create_new, const char *title, const char *text,
|
||||
const char *init_text = nullptr, bool rename = false);
|
||||
bool CreateProfile(const std::string &newName, bool create_new,
|
||||
bool showWizardChecked, bool rename = false);
|
||||
void DeleteProfile(const char *profile_name, const char *profile_dir);
|
||||
void RefreshProfiles();
|
||||
void ChangeProfile();
|
||||
void CheckForSimpleModeX264Fallback();
|
||||
|
||||
void SaveProjectNow();
|
||||
|
||||
int GetTopSelectedSourceItem();
|
||||
@ -742,11 +762,6 @@ public slots:
|
||||
|
||||
bool AddSceneCollection(bool create_new,
|
||||
const QString &name = QString());
|
||||
|
||||
bool NewProfile(const QString &name);
|
||||
bool DuplicateProfile(const QString &name);
|
||||
void DeleteProfile(const QString &profileName);
|
||||
|
||||
void UpdatePatronJson(const QString &text, const QString &error);
|
||||
|
||||
void ShowContextBar();
|
||||
@ -1156,13 +1171,6 @@ private slots:
|
||||
void on_actionExportSceneCollection_triggered();
|
||||
void on_actionRemigrateSceneCollection_triggered();
|
||||
|
||||
void on_actionNewProfile_triggered();
|
||||
void on_actionDupProfile_triggered();
|
||||
void on_actionRenameProfile_triggered();
|
||||
void on_actionRemoveProfile_triggered(bool skipConfirmation = false);
|
||||
void on_actionImportProfile_triggered();
|
||||
void on_actionExportProfile_triggered();
|
||||
|
||||
void on_actionShowSettingsFolder_triggered();
|
||||
void on_actionShowProfileFolder_triggered();
|
||||
|
||||
@ -1337,6 +1345,59 @@ public:
|
||||
void DeleteYouTubeAppDock();
|
||||
YouTubeAppDock *GetYouTubeAppDock();
|
||||
#endif
|
||||
// MARK: - Generic UI Helper Functions
|
||||
OBSPromptResult PromptForName(const OBSPromptRequest &request,
|
||||
const OBSPromptCallback &callback);
|
||||
|
||||
// MARK: - OBS Profile Management
|
||||
private:
|
||||
OBSProfileCache profiles{};
|
||||
|
||||
void SetupNewProfile(const std::string &profileName,
|
||||
bool useWizard = false);
|
||||
void SetupDuplicateProfile(const std::string &profileName);
|
||||
void SetupRenameProfile(const std::string &profileName);
|
||||
|
||||
const OBSProfile &CreateProfile(const std::string &profileName);
|
||||
void RemoveProfile(OBSProfile profile);
|
||||
|
||||
void ChangeProfile();
|
||||
|
||||
void RefreshProfileCache();
|
||||
|
||||
void RefreshProfiles(bool refreshCache = false);
|
||||
|
||||
void ActivateProfile(const OBSProfile &profile, bool reset = false);
|
||||
std::vector<std::string>
|
||||
GetRestartRequirements(const ConfigFile &config) const;
|
||||
void ResetProfileData();
|
||||
void CheckForSimpleModeX264Fallback();
|
||||
|
||||
public:
|
||||
inline const OBSProfileCache &GetProfileCache() const noexcept
|
||||
{
|
||||
return profiles;
|
||||
};
|
||||
|
||||
const OBSProfile &GetCurrentProfile() const;
|
||||
|
||||
std::optional<OBSProfile>
|
||||
GetProfileByName(const std::string &profileName) const;
|
||||
std::optional<OBSProfile>
|
||||
GetProfileByDirectoryName(const std::string &directoryName) const;
|
||||
|
||||
private slots:
|
||||
void on_actionNewProfile_triggered();
|
||||
void on_actionDupProfile_triggered();
|
||||
void on_actionRenameProfile_triggered();
|
||||
void on_actionRemoveProfile_triggered(bool skipConfirmation = false);
|
||||
void on_actionImportProfile_triggered();
|
||||
void on_actionExportProfile_triggered();
|
||||
|
||||
public slots:
|
||||
bool CreateNewProfile(const QString &name);
|
||||
bool CreateDuplicateProfile(const QString &name);
|
||||
void DeleteProfile(const QString &profileName);
|
||||
};
|
||||
|
||||
extern bool cef_js_avail;
|
||||
|
@ -2136,12 +2136,16 @@ OBSBasicSettings::CreateEncoderPropertyView(const char *encoder,
|
||||
OBSPropertiesView *view;
|
||||
|
||||
if (path) {
|
||||
char encoderJsonPath[512];
|
||||
int ret = GetProfilePath(encoderJsonPath,
|
||||
sizeof(encoderJsonPath), path);
|
||||
if (ret > 0) {
|
||||
const OBSBasic *basic =
|
||||
reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
const OBSProfile ¤tProfile = basic->GetCurrentProfile();
|
||||
|
||||
const std::filesystem::path jsonFilePath =
|
||||
currentProfile.path / std::filesystem::u8path(path);
|
||||
|
||||
if (!jsonFilePath.empty()) {
|
||||
obs_data_t *data = obs_data_create_from_json_file_safe(
|
||||
encoderJsonPath, "bak");
|
||||
jsonFilePath.u8string().c_str(), "bak");
|
||||
obs_data_apply(settings, data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
@ -3748,17 +3752,22 @@ static inline const char *SplitFileTypeFromIdx(int idx)
|
||||
|
||||
static void WriteJsonData(OBSPropertiesView *view, const char *path)
|
||||
{
|
||||
char full_path[512];
|
||||
|
||||
if (!view || !WidgetChanged(view))
|
||||
return;
|
||||
|
||||
int ret = GetProfilePath(full_path, sizeof(full_path), path);
|
||||
if (ret > 0) {
|
||||
const OBSBasic *basic =
|
||||
reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
const OBSProfile ¤tProfile = basic->GetCurrentProfile();
|
||||
|
||||
const std::filesystem::path jsonFilePath =
|
||||
currentProfile.path / std::filesystem::u8path(path);
|
||||
|
||||
if (!jsonFilePath.empty()) {
|
||||
obs_data_t *settings = view->GetSettings();
|
||||
if (settings) {
|
||||
obs_data_save_json_safe(settings, full_path, "tmp",
|
||||
"bak");
|
||||
obs_data_save_json_safe(settings,
|
||||
jsonFilePath.u8string().c_str(),
|
||||
"tmp", "bak");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5691,14 +5700,16 @@ void OBSBasicSettings::AdvReplayBufferChanged()
|
||||
if (!settings)
|
||||
return;
|
||||
|
||||
char encoderJsonPath[512];
|
||||
int ret = GetProfilePath(encoderJsonPath,
|
||||
sizeof(encoderJsonPath),
|
||||
"recordEncoder.json");
|
||||
if (ret > 0) {
|
||||
const OBSProfile ¤tProfile = main->GetCurrentProfile();
|
||||
|
||||
const std::filesystem::path jsonFilePath =
|
||||
currentProfile.path /
|
||||
std::filesystem::u8path("recordEncoder.json");
|
||||
|
||||
if (!jsonFilePath.empty()) {
|
||||
OBSDataAutoRelease data =
|
||||
obs_data_create_from_json_file_safe(
|
||||
encoderJsonPath, "bak");
|
||||
jsonFilePath.u8string().c_str(), "bak");
|
||||
obs_data_apply(settings, data);
|
||||
}
|
||||
}
|
||||
|
@ -287,8 +287,8 @@ OBSYoutubeActions::OBSYoutubeActions(QWidget *parent, Auth *auth,
|
||||
workerThread->start();
|
||||
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
bool rememberSettings = config_get_bool(main->basicConfig, "YouTube",
|
||||
"RememberSettings");
|
||||
bool rememberSettings = config_get_bool(main->activeConfiguration,
|
||||
"YouTube", "RememberSettings");
|
||||
if (rememberSettings)
|
||||
LoadSettings();
|
||||
|
||||
@ -749,83 +749,85 @@ void OBSYoutubeActions::SaveSettings(BroadcastDescription &broadcast)
|
||||
{
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
|
||||
config_set_string(main->basicConfig, "YouTube", "Title",
|
||||
config_set_string(main->activeConfiguration, "YouTube", "Title",
|
||||
QT_TO_UTF8(broadcast.title));
|
||||
config_set_string(main->basicConfig, "YouTube", "Description",
|
||||
config_set_string(main->activeConfiguration, "YouTube", "Description",
|
||||
QT_TO_UTF8(broadcast.description));
|
||||
config_set_string(main->basicConfig, "YouTube", "Privacy",
|
||||
config_set_string(main->activeConfiguration, "YouTube", "Privacy",
|
||||
QT_TO_UTF8(broadcast.privacy));
|
||||
config_set_string(main->basicConfig, "YouTube", "CategoryID",
|
||||
config_set_string(main->activeConfiguration, "YouTube", "CategoryID",
|
||||
QT_TO_UTF8(broadcast.category.id));
|
||||
config_set_string(main->basicConfig, "YouTube", "Latency",
|
||||
config_set_string(main->activeConfiguration, "YouTube", "Latency",
|
||||
QT_TO_UTF8(broadcast.latency));
|
||||
config_set_bool(main->basicConfig, "YouTube", "MadeForKids",
|
||||
config_set_bool(main->activeConfiguration, "YouTube", "MadeForKids",
|
||||
broadcast.made_for_kids);
|
||||
config_set_bool(main->basicConfig, "YouTube", "AutoStart",
|
||||
config_set_bool(main->activeConfiguration, "YouTube", "AutoStart",
|
||||
broadcast.auto_start);
|
||||
config_set_bool(main->basicConfig, "YouTube", "AutoStop",
|
||||
config_set_bool(main->activeConfiguration, "YouTube", "AutoStop",
|
||||
broadcast.auto_start);
|
||||
config_set_bool(main->basicConfig, "YouTube", "DVR", broadcast.dvr);
|
||||
config_set_bool(main->basicConfig, "YouTube", "ScheduleForLater",
|
||||
broadcast.schedul_for_later);
|
||||
config_set_string(main->basicConfig, "YouTube", "Projection",
|
||||
config_set_bool(main->activeConfiguration, "YouTube", "DVR",
|
||||
broadcast.dvr);
|
||||
config_set_bool(main->activeConfiguration, "YouTube",
|
||||
"ScheduleForLater", broadcast.schedul_for_later);
|
||||
config_set_string(main->activeConfiguration, "YouTube", "Projection",
|
||||
QT_TO_UTF8(broadcast.projection));
|
||||
config_set_string(main->basicConfig, "YouTube", "ThumbnailFile",
|
||||
config_set_string(main->activeConfiguration, "YouTube", "ThumbnailFile",
|
||||
QT_TO_UTF8(thumbnailFile));
|
||||
config_set_bool(main->basicConfig, "YouTube", "RememberSettings", true);
|
||||
config_set_bool(main->activeConfiguration, "YouTube",
|
||||
"RememberSettings", true);
|
||||
}
|
||||
|
||||
void OBSYoutubeActions::LoadSettings()
|
||||
{
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
|
||||
const char *title =
|
||||
config_get_string(main->basicConfig, "YouTube", "Title");
|
||||
const char *title = config_get_string(main->activeConfiguration,
|
||||
"YouTube", "Title");
|
||||
ui->title->setText(QT_UTF8(title));
|
||||
|
||||
const char *desc =
|
||||
config_get_string(main->basicConfig, "YouTube", "Description");
|
||||
const char *desc = config_get_string(main->activeConfiguration,
|
||||
"YouTube", "Description");
|
||||
ui->description->setPlainText(QT_UTF8(desc));
|
||||
|
||||
const char *priv =
|
||||
config_get_string(main->basicConfig, "YouTube", "Privacy");
|
||||
const char *priv = config_get_string(main->activeConfiguration,
|
||||
"YouTube", "Privacy");
|
||||
int index = ui->privacyBox->findData(priv);
|
||||
ui->privacyBox->setCurrentIndex(index);
|
||||
|
||||
const char *catID =
|
||||
config_get_string(main->basicConfig, "YouTube", "CategoryID");
|
||||
const char *catID = config_get_string(main->activeConfiguration,
|
||||
"YouTube", "CategoryID");
|
||||
index = ui->categoryBox->findData(catID);
|
||||
ui->categoryBox->setCurrentIndex(index);
|
||||
|
||||
const char *latency =
|
||||
config_get_string(main->basicConfig, "YouTube", "Latency");
|
||||
const char *latency = config_get_string(main->activeConfiguration,
|
||||
"YouTube", "Latency");
|
||||
index = ui->latencyBox->findData(latency);
|
||||
ui->latencyBox->setCurrentIndex(index);
|
||||
|
||||
bool dvr = config_get_bool(main->basicConfig, "YouTube", "DVR");
|
||||
bool dvr = config_get_bool(main->activeConfiguration, "YouTube", "DVR");
|
||||
ui->checkDVR->setChecked(dvr);
|
||||
|
||||
bool forKids =
|
||||
config_get_bool(main->basicConfig, "YouTube", "MadeForKids");
|
||||
bool forKids = config_get_bool(main->activeConfiguration, "YouTube",
|
||||
"MadeForKids");
|
||||
if (forKids)
|
||||
ui->yesMakeForKids->setChecked(true);
|
||||
else
|
||||
ui->notMakeForKids->setChecked(true);
|
||||
|
||||
bool schedLater = config_get_bool(main->basicConfig, "YouTube",
|
||||
bool schedLater = config_get_bool(main->activeConfiguration, "YouTube",
|
||||
"ScheduleForLater");
|
||||
ui->checkScheduledLater->setChecked(schedLater);
|
||||
|
||||
bool autoStart =
|
||||
config_get_bool(main->basicConfig, "YouTube", "AutoStart");
|
||||
bool autoStart = config_get_bool(main->activeConfiguration, "YouTube",
|
||||
"AutoStart");
|
||||
ui->checkAutoStart->setChecked(autoStart);
|
||||
|
||||
bool autoStop =
|
||||
config_get_bool(main->basicConfig, "YouTube", "AutoStop");
|
||||
bool autoStop = config_get_bool(main->activeConfiguration, "YouTube",
|
||||
"AutoStop");
|
||||
ui->checkAutoStop->setChecked(autoStop);
|
||||
|
||||
const char *projection =
|
||||
config_get_string(main->basicConfig, "YouTube", "Projection");
|
||||
const char *projection = config_get_string(main->activeConfiguration,
|
||||
"YouTube", "Projection");
|
||||
if (projection && *projection) {
|
||||
if (strcmp(projection, "360") == 0)
|
||||
ui->check360Video->setChecked(true);
|
||||
@ -833,8 +835,8 @@ void OBSYoutubeActions::LoadSettings()
|
||||
ui->check360Video->setChecked(false);
|
||||
}
|
||||
|
||||
const char *thumbFile = config_get_string(main->basicConfig, "YouTube",
|
||||
"ThumbnailFile");
|
||||
const char *thumbFile = config_get_string(main->activeConfiguration,
|
||||
"YouTube", "ThumbnailFile");
|
||||
if (thumbFile && *thumbFile) {
|
||||
QFileInfo tFile(thumbFile);
|
||||
// Re-check validity before setting path again
|
||||
|
Loading…
x
Reference in New Issue
Block a user