mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-15 07:44:10 +00:00
parent
0bf09160e5
commit
de66aeab68
|
@ -39,6 +39,16 @@ else()
|
|||
set(MIXER_ENABLED TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED RESTREAM_CLIENTID OR "${RESTREAM_CLIENTID}" STREQUAL "" OR
|
||||
NOT DEFINED RESTREAM_HASH OR "${RESTREAM_HASH}" STREQUAL "" OR
|
||||
NOT BROWSER_AVAILABLE_INTERNAL)
|
||||
set(RESTREAM_ENABLED FALSE)
|
||||
set(RESTREAM_CLIENTID "")
|
||||
set(RESTREAM_HASH "0")
|
||||
else()
|
||||
set(RESTREAM_ENABLED TRUE)
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/ui-config.h.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/ui-config.h")
|
||||
|
@ -159,6 +169,15 @@ if(BROWSER_AVAILABLE_INTERNAL)
|
|||
auth-mixer.hpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(RESTREAM_ENABLED)
|
||||
list(APPEND obs_PLATFORM_SOURCES
|
||||
auth-restream.cpp
|
||||
)
|
||||
list(APPEND obs_PLATFORM_HEADERS
|
||||
auth-restream.hpp
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(obs_libffutil_SOURCES
|
||||
|
|
283
UI/auth-restream.cpp
Normal file
283
UI/auth-restream.cpp
Normal file
|
@ -0,0 +1,283 @@
|
|||
#include "auth-restream.hpp"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <qt-wrappers.hpp>
|
||||
#include <json11.hpp>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
|
||||
#include <obs-app.hpp>
|
||||
#include "window-basic-main.hpp"
|
||||
#include "remote-text.hpp"
|
||||
#include "ui-config.h"
|
||||
#include "obf.h"
|
||||
#include <browser-panel.hpp>
|
||||
|
||||
using namespace json11;
|
||||
|
||||
extern QCef *cef;
|
||||
extern QCefCookieManager *panel_cookies;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define RESTREAM_AUTH_URL "https://obsproject.com/app-auth/restream?action=redirect"
|
||||
#define RESTREAM_TOKEN_URL "https://obsproject.com/app-auth/restream-token"
|
||||
#define RESTREAM_STREAMKEY_URL "https://api.restream.io/v2/user/streamKey"
|
||||
#define RESTREAM_SCOPE_VERSION 1
|
||||
|
||||
|
||||
static Auth::Def restreamDef = {
|
||||
"Restream",
|
||||
Auth::Type::OAuth_StreamKey
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
RestreamAuth::RestreamAuth(const Def &d)
|
||||
: OAuthStreamKey(d)
|
||||
{
|
||||
}
|
||||
|
||||
bool RestreamAuth::GetChannelInfo()
|
||||
try {
|
||||
std::string client_id = RESTREAM_CLIENTID;
|
||||
deobfuscate_str(&client_id[0], RESTREAM_HASH);
|
||||
|
||||
if (!GetToken(RESTREAM_TOKEN_URL, client_id, RESTREAM_SCOPE_VERSION))
|
||||
return false;
|
||||
if (token.empty())
|
||||
return false;
|
||||
if (!key_.empty())
|
||||
return true;
|
||||
|
||||
std::string auth;
|
||||
auth += "Authorization: Bearer ";
|
||||
auth += token;
|
||||
|
||||
std::vector<std::string> headers;
|
||||
headers.push_back(std::string("Client-ID: ") + client_id);
|
||||
headers.push_back(std::move(auth));
|
||||
|
||||
std::string output;
|
||||
std::string error;
|
||||
Json json;
|
||||
bool success;
|
||||
|
||||
auto func = [&] () {
|
||||
success = GetRemoteFile(
|
||||
RESTREAM_STREAMKEY_URL,
|
||||
output,
|
||||
error,
|
||||
nullptr,
|
||||
"application/json",
|
||||
nullptr,
|
||||
headers,
|
||||
nullptr,
|
||||
5);
|
||||
};
|
||||
|
||||
ExecThreadedWithoutBlocking(
|
||||
func,
|
||||
QTStr("Auth.LoadingChannel.Title"),
|
||||
QTStr("Auth.LoadingChannel.Text").arg(service()));
|
||||
if (!success || output.empty())
|
||||
throw ErrorInfo("Failed to get stream key from remote", error);
|
||||
|
||||
json = Json::parse(output, error);
|
||||
if (!error.empty())
|
||||
throw ErrorInfo("Failed to parse json", error);
|
||||
|
||||
error = json["error"].string_value();
|
||||
if (!error.empty())
|
||||
throw ErrorInfo(error, json["error_description"].string_value());
|
||||
|
||||
key_ = json["streamKey"].string_value();
|
||||
|
||||
return true;
|
||||
} catch (ErrorInfo info) {
|
||||
QString title = QTStr("Auth.ChannelFailure.Title");
|
||||
QString text = QTStr("Auth.ChannelFailure.Text")
|
||||
.arg(service(), info.message.c_str(), info.error.c_str());
|
||||
|
||||
QMessageBox::warning(OBSBasic::Get(), title, text);
|
||||
|
||||
blog(LOG_WARNING, "%s: %s: %s",
|
||||
__FUNCTION__,
|
||||
info.message.c_str(),
|
||||
info.error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void RestreamAuth::SaveInternal()
|
||||
{
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
config_set_string(main->Config(), service(), "DockState",
|
||||
main->saveState().toBase64().constData());
|
||||
OAuthStreamKey::SaveInternal();
|
||||
}
|
||||
|
||||
static inline std::string get_config_str(
|
||||
OBSBasic *main,
|
||||
const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *val = config_get_string(main->Config(), section, name);
|
||||
return val ? val : "";
|
||||
}
|
||||
|
||||
bool RestreamAuth::LoadInternal()
|
||||
{
|
||||
firstLoad = false;
|
||||
return OAuthStreamKey::LoadInternal();
|
||||
}
|
||||
|
||||
class RestreamWidget : public QDockWidget {
|
||||
public:
|
||||
inline RestreamWidget() : QDockWidget() {}
|
||||
|
||||
QScopedPointer<QCefWidget> widget;
|
||||
};
|
||||
|
||||
void RestreamAuth::LoadUI()
|
||||
{
|
||||
if (uiLoaded)
|
||||
return;
|
||||
if (!GetChannelInfo())
|
||||
return;
|
||||
|
||||
OBSBasic::InitBrowserPanelSafeBlock();
|
||||
OBSBasic *main = OBSBasic::Get();
|
||||
|
||||
QCefWidget *browser;
|
||||
std::string url;
|
||||
std::string script;
|
||||
|
||||
/* ----------------------------------- */
|
||||
|
||||
url = "https://restream.io/chat-application";
|
||||
|
||||
QSize size = main->frameSize();
|
||||
QPoint pos = main->pos();
|
||||
|
||||
chat.reset(new RestreamWidget());
|
||||
chat->setObjectName("restreamChat");
|
||||
chat->resize(420, 600);
|
||||
chat->setMinimumSize(380, 300);
|
||||
chat->setWindowTitle(QTStr("Auth.Chat"));
|
||||
chat->setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||
|
||||
browser = cef->create_widget(nullptr, url, panel_cookies);
|
||||
chat->setWidget(browser);
|
||||
|
||||
main->addDockWidget(Qt::RightDockWidgetArea, chat.data());
|
||||
chatMenu.reset(main->AddDockWidget(chat.data()));
|
||||
|
||||
/* ----------------------------------- */
|
||||
|
||||
url = "https://restream.io/titles/embed";
|
||||
|
||||
info.reset(new RestreamWidget());
|
||||
info->setObjectName("restreamInfo");
|
||||
info->resize(410, 600);
|
||||
info->setMinimumSize(380, 300);
|
||||
info->setWindowTitle(QTStr("Auth.StreamInfo"));
|
||||
info->setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||
|
||||
browser = cef->create_widget(nullptr, url, panel_cookies);
|
||||
info->setWidget(browser);
|
||||
|
||||
main->addDockWidget(Qt::RightDockWidgetArea, info.data());
|
||||
infoMenu.reset(main->AddDockWidget(info.data()));
|
||||
|
||||
/* ----------------------------------- */
|
||||
|
||||
chat->setFloating(true);
|
||||
info->setFloating(true);
|
||||
chat->move(pos.x() + size.width() - chat->width() - 50, pos.y() + 50);
|
||||
info->move(pos.x() + 40, pos.y() + 50);
|
||||
|
||||
if (firstLoad) {
|
||||
chat->setVisible(true);
|
||||
info->setVisible(true);
|
||||
}
|
||||
else {
|
||||
const char *dockStateStr = config_get_string(main->Config(),
|
||||
service(), "DockState");
|
||||
QByteArray dockState =
|
||||
QByteArray::fromBase64(QByteArray(dockStateStr));
|
||||
main->restoreState(dockState);
|
||||
}
|
||||
|
||||
uiLoaded = true;
|
||||
}
|
||||
|
||||
bool RestreamAuth::RetryLogin()
|
||||
{
|
||||
OAuthLogin login(OBSBasic::Get(), RESTREAM_AUTH_URL, false);
|
||||
cef->add_popup_whitelist_url("about:blank", &login);
|
||||
if (login.exec() == QDialog::Rejected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<RestreamAuth> auth =
|
||||
std::make_shared<RestreamAuth>(restreamDef);
|
||||
|
||||
std::string client_id = RESTREAM_CLIENTID;
|
||||
deobfuscate_str(&client_id[0], RESTREAM_HASH);
|
||||
|
||||
return GetToken(RESTREAM_TOKEN_URL, client_id,
|
||||
RESTREAM_SCOPE_VERSION,
|
||||
QT_TO_UTF8(login.GetCode()), true);
|
||||
}
|
||||
|
||||
std::shared_ptr<Auth> RestreamAuth::Login(QWidget *parent)
|
||||
{
|
||||
OAuthLogin login(parent, RESTREAM_AUTH_URL, false);
|
||||
cef->add_popup_whitelist_url("about:blank", &login);
|
||||
|
||||
if (login.exec() == QDialog::Rejected) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<RestreamAuth> auth =
|
||||
std::make_shared<RestreamAuth>(restreamDef);
|
||||
|
||||
std::string client_id = RESTREAM_CLIENTID;
|
||||
deobfuscate_str(&client_id[0], RESTREAM_HASH);
|
||||
|
||||
if (!auth->GetToken(RESTREAM_TOKEN_URL, client_id,
|
||||
RESTREAM_SCOPE_VERSION,
|
||||
QT_TO_UTF8(login.GetCode()))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
if (auth->GetChannelInfo()) {
|
||||
return auth;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::shared_ptr<Auth> CreateRestreamAuth()
|
||||
{
|
||||
return std::make_shared<RestreamAuth>(restreamDef);
|
||||
}
|
||||
|
||||
static void DeleteCookies()
|
||||
{
|
||||
if (panel_cookies) {
|
||||
panel_cookies->DeleteCookies("restream.io", std::string());
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterRestreamAuth()
|
||||
{
|
||||
OAuth::RegisterOAuth(
|
||||
restreamDef,
|
||||
CreateRestreamAuth,
|
||||
RestreamAuth::Login,
|
||||
DeleteCookies);
|
||||
}
|
29
UI/auth-restream.hpp
Normal file
29
UI/auth-restream.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "auth-oauth.hpp"
|
||||
|
||||
class RestreamWidget;
|
||||
|
||||
class RestreamAuth : public OAuthStreamKey {
|
||||
Q_OBJECT
|
||||
|
||||
QSharedPointer<RestreamWidget> chat;
|
||||
QSharedPointer<RestreamWidget> info;
|
||||
QSharedPointer<QAction> chatMenu;
|
||||
QSharedPointer<QAction> infoMenu;
|
||||
bool uiLoaded = false;
|
||||
|
||||
virtual bool RetryLogin() override;
|
||||
|
||||
virtual void SaveInternal() override;
|
||||
virtual bool LoadInternal() override;
|
||||
|
||||
bool GetChannelInfo();
|
||||
|
||||
virtual void LoadUI() override;
|
||||
|
||||
public:
|
||||
RestreamAuth(const Def &d);
|
||||
|
||||
static std::shared_ptr<Auth> Login(QWidget *parent);
|
||||
};
|
|
@ -23,3 +23,7 @@
|
|||
#define MIXER_ENABLED @MIXER_ENABLED@
|
||||
#define MIXER_CLIENTID "@MIXER_CLIENTID@"
|
||||
#define MIXER_HASH 0x@MIXER_HASH@
|
||||
|
||||
#define RESTREAM_ENABLED @RESTREAM_ENABLED@
|
||||
#define RESTREAM_CLIENTID "@RESTREAM_CLIENTID@"
|
||||
#define RESTREAM_HASH 0x@RESTREAM_HASH@
|
||||
|
|
|
@ -193,6 +193,7 @@ void assignDockToggle(QDockWidget *dock, QAction *action)
|
|||
|
||||
extern void RegisterTwitchAuth();
|
||||
extern void RegisterMixerAuth();
|
||||
extern void RegisterRestreamAuth();
|
||||
|
||||
OBSBasic::OBSBasic(QWidget *parent)
|
||||
: OBSMainWindow (parent),
|
||||
|
@ -206,6 +207,9 @@ OBSBasic::OBSBasic(QWidget *parent)
|
|||
#if MIXER_ENABLED
|
||||
RegisterMixerAuth();
|
||||
#endif
|
||||
#if RESTREAM_ENABLED
|
||||
RegisterRestreamAuth();
|
||||
#endif
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
|
|
Loading…
Reference in a new issue