Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
小白菜888
Obs Studio
提交
4710c042
O
Obs Studio
项目概览
小白菜888
/
Obs Studio
通知
4
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
Obs Studio
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
4710c042
编写于
2月 06, 2019
作者:
J
jp9000
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
UI: Add Mixer integration
上级
67bb8d70
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
394 addition
and
0 deletion
+394
-0
UI/CMakeLists.txt
UI/CMakeLists.txt
+24
-0
UI/auth-mixer.cpp
UI/auth-mixer.cpp
+310
-0
UI/auth-mixer.hpp
UI/auth-mixer.hpp
+30
-0
UI/data/locale/en-US.ini
UI/data/locale/en-US.ini
+1
-0
UI/ui-config.h.in
UI/ui-config.h.in
+21
-0
UI/window-basic-main.cpp
UI/window-basic-main.cpp
+8
-0
未找到文件。
UI/CMakeLists.txt
浏览文件 @
4710c042
...
...
@@ -19,6 +19,20 @@ project(obs)
set
(
DISABLE_UPDATE_MODULE TRUE CACHE BOOL
"Disables building the update module"
)
if
(
NOT DEFINED MIXER_CLIENTID OR
"
${
MIXER_CLIENTID
}
"
STREQUAL
""
OR
NOT DEFINED MIXER_HASH OR
"
${
MIXER_HASH
}
"
STREQUAL
""
OR
NOT BROWSER_AVAILABLE_INTERNAL
)
set
(
MIXER_ENABLED FALSE
)
set
(
MIXER_CLIENTID
""
)
set
(
MIXER_HASH
"0"
)
else
()
set
(
MIXER_ENABLED TRUE
)
endif
()
configure_file
(
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/ui-config.h.in"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/ui-config.h"
)
set
(
CMAKE_INCLUDE_CURRENT_DIR TRUE
)
set
(
CMAKE_AUTOMOC TRUE
)
...
...
@@ -39,6 +53,7 @@ endif()
include_directories
(
${
FFMPEG_INCLUDE_DIRS
}
)
include_directories
(
${
CMAKE_CURRENT_BINARY_DIR
}
)
include_directories
(
SYSTEM
"obs-frontend-api"
)
include_directories
(
SYSTEM
"
${
CMAKE_SOURCE_DIR
}
/libobs"
)
include_directories
(
SYSTEM
"
${
CMAKE_SOURCE_DIR
}
/deps/libff"
)
...
...
@@ -114,6 +129,15 @@ if(BROWSER_AVAILABLE_INTERNAL)
obf.h
auth-oauth.hpp
)
if
(
MIXER_ENABLED
)
list
(
APPEND obs_PLATFORM_SOURCES
auth-mixer.cpp
)
list
(
APPEND obs_PLATFORM_HEADERS
auth-mixer.hpp
)
endif
()
endif
()
set
(
obs_libffutil_SOURCES
...
...
UI/auth-mixer.cpp
0 → 100644
浏览文件 @
4710c042
#include "auth-mixer.hpp"
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <qt-wrappers.hpp>
#include <obs-app.hpp>
#include "window-basic-main.hpp"
#include "remote-text.hpp"
#include <json11.hpp>
#include <ctime>
#include "ui-config.h"
#include "obf.h"
using
namespace
json11
;
#include <browser-panel.hpp>
extern
QCef
*
cef
;
extern
QCefCookieManager
*
panel_cookies
;
/* ------------------------------------------------------------------------- */
#define MIXER_AUTH_URL \
"https://obsproject.com/app-auth/mixer?action=redirect"
#define MIXER_TOKEN_URL \
"https://obsproject.com/app-auth/mixer-token"
#define MIXER_SCOPE_VERSION 1
static
Auth
::
Def
mixerDef
=
{
"Mixer"
,
Auth
::
Type
::
OAuth_StreamKey
};
/* ------------------------------------------------------------------------- */
MixerAuth
::
MixerAuth
(
const
Def
&
d
)
:
OAuthStreamKey
(
d
)
{
}
bool
MixerAuth
::
GetChannelInfo
()
try
{
std
::
string
client_id
=
MIXER_CLIENTID
;
deobfuscate_str
(
&
client_id
[
0
],
MIXER_HASH
);
if
(
!
GetToken
(
MIXER_TOKEN_URL
,
client_id
,
MIXER_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
;
if
(
id
.
empty
())
{
auto
func
=
[
&
]
()
{
success
=
GetRemoteFile
(
"https://mixer.com/api/v1/users/current"
,
output
,
error
,
nullptr
,
"application/json"
,
nullptr
,
headers
,
nullptr
,
5
);
};
ExecuteFuncSafeBlockMsgBox
(
func
,
QTStr
(
"Auth.LoadingChannel.Title"
),
QTStr
(
"Auth.LoadingChannel.Text"
).
arg
(
service
()));
if
(
!
success
||
output
.
empty
())
throw
ErrorInfo
(
"Failed to get user info from remote"
,
error
);
Json
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
());
id
=
std
::
to_string
(
json
[
"channel"
][
"id"
].
int_value
());
name
=
json
[
"channel"
][
"token"
].
string_value
();
}
/* ------------------ */
std
::
string
url
;
url
+=
"https://mixer.com/api/v1/channels/"
;
url
+=
id
;
url
+=
"/details"
;
output
.
clear
();
auto
func
=
[
&
]
()
{
success
=
GetRemoteFile
(
url
.
c_str
(),
output
,
error
,
nullptr
,
"application/json"
,
nullptr
,
headers
,
nullptr
,
5
);
};
ExecuteFuncSafeBlockMsgBox
(
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_
=
id
+
"-"
+
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
MixerAuth
::
SaveInternal
()
{
OBSBasic
*
main
=
OBSBasic
::
Get
();
config_set_string
(
main
->
Config
(),
service
(),
"Name"
,
name
.
c_str
());
config_set_string
(
main
->
Config
(),
service
(),
"Id"
,
id
.
c_str
());
if
(
uiLoaded
)
{
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
MixerAuth
::
LoadInternal
()
{
OBSBasic
*
main
=
OBSBasic
::
Get
();
name
=
get_config_str
(
main
,
service
(),
"Name"
);
id
=
get_config_str
(
main
,
service
(),
"Id"
);
firstLoad
=
false
;
return
OAuthStreamKey
::
LoadInternal
();
}
class
MixerChat
:
public
QDockWidget
{
public:
inline
MixerChat
()
:
QDockWidget
()
{}
QScopedPointer
<
QCefWidget
>
widget
;
};
void
MixerAuth
::
LoadUI
()
{
if
(
uiLoaded
)
return
;
if
(
!
GetChannelInfo
())
return
;
OBSBasic
::
InitBrowserPanelSafeBlock
(
true
);
OBSBasic
*
main
=
OBSBasic
::
Get
();
std
::
string
url
;
url
+=
"https://mixer.com/embed/chat/"
;
url
+=
id
;
QSize
size
=
main
->
frameSize
();
QPoint
pos
=
main
->
pos
();
chat
.
reset
(
new
MixerChat
());
chat
->
setObjectName
(
"mixerChat"
);
chat
->
resize
(
300
,
600
);
chat
->
setMinimumSize
(
200
,
300
);
chat
->
setWindowTitle
(
QTStr
(
"Auth.Chat"
));
chat
->
setAllowedAreas
(
Qt
::
AllDockWidgetAreas
);
QCefWidget
*
browser
=
cef
->
create_widget
(
nullptr
,
url
,
panel_cookies
);
chat
->
setWidget
(
browser
);
main
->
addDockWidget
(
Qt
::
RightDockWidgetArea
,
chat
.
data
());
chatMenu
.
reset
(
main
->
AddDockWidget
(
chat
.
data
()));
/* ----------------------------------- */
chat
->
setFloating
(
true
);
chat
->
move
(
pos
.
x
()
+
size
.
width
()
-
chat
->
width
()
-
50
,
pos
.
y
()
+
50
);
if
(
firstLoad
)
{
chat
->
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
MixerAuth
::
RetryLogin
()
{
OAuthLogin
login
(
OBSBasic
::
Get
(),
MIXER_AUTH_URL
,
false
);
cef
->
add_popup_whitelist_url
(
"about:blank"
,
&
login
);
if
(
login
.
exec
()
==
QDialog
::
Rejected
)
{
return
false
;
}
std
::
shared_ptr
<
MixerAuth
>
auth
=
std
::
make_shared
<
MixerAuth
>
(
mixerDef
);
std
::
string
client_id
=
MIXER_CLIENTID
;
deobfuscate_str
(
&
client_id
[
0
],
MIXER_HASH
);
return
GetToken
(
MIXER_TOKEN_URL
,
client_id
,
MIXER_SCOPE_VERSION
,
QT_TO_UTF8
(
login
.
GetCode
()),
true
);
}
std
::
shared_ptr
<
Auth
>
MixerAuth
::
Login
(
QWidget
*
parent
)
{
OAuthLogin
login
(
parent
,
MIXER_AUTH_URL
,
false
);
cef
->
add_popup_whitelist_url
(
"about:blank"
,
&
login
);
if
(
login
.
exec
()
==
QDialog
::
Rejected
)
{
return
nullptr
;
}
std
::
shared_ptr
<
MixerAuth
>
auth
=
std
::
make_shared
<
MixerAuth
>
(
mixerDef
);
std
::
string
client_id
=
TWITCH_CLIENTID
;
deobfuscate_str
(
&
client_id
[
0
],
TWITCH_HASH
);
if
(
!
auth
->
GetToken
(
MIXER_TOKEN_URL
,
client_id
,
MIXER_SCOPE_VERSION
,
QT_TO_UTF8
(
login
.
GetCode
())))
{
return
nullptr
;
}
std
::
string
error
;
if
(
auth
->
GetChannelInfo
())
{
return
auth
;
}
return
nullptr
;
}
static
std
::
shared_ptr
<
Auth
>
CreateMixerAuth
()
{
return
std
::
make_shared
<
MixerAuth
>
(
mixerDef
);
}
static
void
DeleteCookies
()
{
if
(
panel_cookies
)
{
panel_cookies
->
DeleteCookies
(
"mixer.com"
,
std
::
string
());
panel_cookies
->
DeleteCookies
(
"microsoft.com"
,
std
::
string
());
}
}
void
RegisterMixerAuth
()
{
OAuth
::
RegisterOAuth
(
mixerDef
,
CreateMixerAuth
,
MixerAuth
::
Login
,
DeleteCookies
);
}
UI/auth-mixer.hpp
0 → 100644
浏览文件 @
4710c042
#pragma once
#include "auth-oauth.hpp"
class
MixerChat
;
class
MixerAuth
:
public
OAuthStreamKey
{
Q_OBJECT
QSharedPointer
<
MixerChat
>
chat
;
QSharedPointer
<
QAction
>
chatMenu
;
bool
uiLoaded
=
false
;
std
::
string
name
;
std
::
string
id
;
virtual
bool
RetryLogin
()
override
;
virtual
void
SaveInternal
()
override
;
virtual
bool
LoadInternal
()
override
;
bool
GetChannelInfo
();
virtual
void
LoadUI
()
override
;
public:
MixerAuth
(
const
Def
&
d
);
static
std
::
shared_ptr
<
Auth
>
Login
(
QWidget
*
parent
);
};
UI/data/locale/en-US.ini
浏览文件 @
4710c042
...
...
@@ -102,6 +102,7 @@ Auth.LoadingChannel.Title="Loading channel information.."
Auth.LoadingChannel.Text
=
"Loading channel information for %1, please wait.."
Auth.ChannelFailure.Title
=
"Failed to load channel"
Auth.ChannelFailure.Text
=
"Failed to load channel information for %1
\n\n
%2: %3"
Auth.Chat
=
"Chat"
# copy filters
Copy.Filters
=
"Copy Filters"
...
...
UI/ui-config.h.in
0 → 100644
浏览文件 @
4710c042
#pragma once
#ifndef TRUE
#define TRUE 1
#endif
#ifndef ON
#define ON 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef OFF
#define OFF 0
#endif
#define MIXER_ENABLED @MIXER_ENABLED@
#define MIXER_CLIENTID "@MIXER_CLIENTID@"
#define MIXER_HASH 0x@MIXER_HASH@
UI/window-basic-main.cpp
浏览文件 @
4710c042
...
...
@@ -78,6 +78,8 @@ using namespace std;
#include <browser-panel.hpp>
#endif
#include "ui-config.h"
struct
QCef
;
struct
QCefCookieManager
;
...
...
@@ -189,12 +191,18 @@ void assignDockToggle(QDockWidget *dock, QAction *action)
handleMenuToggle
);
}
extern
void
RegisterMixerAuth
();
OBSBasic
::
OBSBasic
(
QWidget
*
parent
)
:
OBSMainWindow
(
parent
),
ui
(
new
Ui
::
OBSBasic
)
{
setAttribute
(
Qt
::
WA_NativeWindow
);
#if MIXER_ENABLED
RegisterMixerAuth
();
#endif
setAcceptDrops
(
true
);
api
=
InitializeAPIInterface
(
this
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录