mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-16 06:08:12 -05:00
Add channel selection
This commit is contained in:
@@ -39,6 +39,8 @@ target_sources(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE category-selection.cpp
|
||||
category-selection.hpp
|
||||
channel-selection.cpp
|
||||
channel-selection.hpp
|
||||
macro-action-twitch.cpp
|
||||
macro-action-twitch.hpp
|
||||
token.cpp
|
||||
|
||||
217
src/macro-external/twitch/channel-selection.cpp
Normal file
217
src/macro-external/twitch/channel-selection.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
#include "channel-selection.hpp"
|
||||
#include "twitch-helpers.hpp"
|
||||
#include "token.hpp"
|
||||
|
||||
#include <QLayout>
|
||||
#include <QDesktopServices>
|
||||
#include <obs-module-helper.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
bool ChannelLiveInfo::IsLive() const
|
||||
{
|
||||
return type == "live";
|
||||
}
|
||||
|
||||
void TwitchChannel::Load(obs_data_t *obj)
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "channel");
|
||||
_name.Load(data, "name");
|
||||
}
|
||||
|
||||
void TwitchChannel::Save(obs_data_t *obj) const
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
_name.Save(data, "name");
|
||||
obs_data_set_obj(obj, "channel", data);
|
||||
}
|
||||
|
||||
std::string TwitchChannel::GetUserID(const TwitchToken &token)
|
||||
{
|
||||
static std::map<std::string, std::string> userIDCache;
|
||||
auto it = userIDCache.find(std::string(_name));
|
||||
if (it != userIDCache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto res = SendGetRequest("https://api.twitch.tv", "/helix/users",
|
||||
token, {{"login", _name}});
|
||||
|
||||
if (res.status == 400) {
|
||||
userIDCache[_name] = "invalid";
|
||||
blog(LOG_INFO, "ignoring invalid channel selection '%s'!",
|
||||
_name.c_str());
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
if (res.status != 200) {
|
||||
blog(LOG_INFO, "failed to get Twitch user id from token! (%d)",
|
||||
res.status);
|
||||
return "invalid";
|
||||
}
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(res.data, "data");
|
||||
size_t count = obs_data_array_count(array);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
OBSDataAutoRelease arrayObj = obs_data_array_item(array, i);
|
||||
std::string id = obs_data_get_string(arrayObj, "id");
|
||||
userIDCache[_name] = id;
|
||||
return id;
|
||||
}
|
||||
userIDCache[_name] = "invalid";
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
static QDate parseRFC3339Date(const std::string &rfc3339Date)
|
||||
{
|
||||
QString rfc3339QString = QString::fromStdString(rfc3339Date);
|
||||
QRegularExpression regex("(\\d{4})-(\\d{2})-(\\d{2})");
|
||||
QRegularExpressionMatch match = regex.match(rfc3339QString);
|
||||
|
||||
if (match.hasMatch()) {
|
||||
int year = match.captured(1).toInt();
|
||||
int month = match.captured(2).toInt();
|
||||
int day = match.captured(3).toInt();
|
||||
QDate date(year, month, day);
|
||||
return date;
|
||||
} else {
|
||||
return QDate();
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string>
|
||||
getStringArrayHelper(const OBSDataAutoRelease &data, const std::string &value)
|
||||
{
|
||||
static std::vector<std::string> result;
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(data, value.c_str());
|
||||
size_t count = obs_data_array_count(array);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
// TODO
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<ChannelLiveInfo>
|
||||
TwitchChannel::GetLiveInfo(const TwitchToken &token)
|
||||
{
|
||||
auto id = GetUserID(token);
|
||||
if (!IsValid(id)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
httplib::Params params = {
|
||||
{"first", "1"}, {"after", ""}, {"user_id", id}};
|
||||
auto result = SendGetRequest("https://api.twitch.tv", "/helix/streams",
|
||||
token, params, true);
|
||||
if (result.status != 200) {
|
||||
return {};
|
||||
}
|
||||
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(result.data, "data");
|
||||
size_t count = obs_data_array_count(array);
|
||||
if (count == 0) {
|
||||
return {};
|
||||
}
|
||||
OBSDataAutoRelease data = obs_data_array_item(array, 0);
|
||||
|
||||
ChannelLiveInfo info;
|
||||
info.id = obs_data_get_string(data, "id");
|
||||
info.user_id = obs_data_get_string(data, "user_id");
|
||||
info.user_login = obs_data_get_string(data, "user_login");
|
||||
info.user_name = obs_data_get_string(data, "user_name");
|
||||
info.game_id = obs_data_get_string(data, "game_id");
|
||||
info.game_name = obs_data_get_string(data, "game_name");
|
||||
info.type = obs_data_get_string(data, "type");
|
||||
info.title = obs_data_get_string(data, "title");
|
||||
info.tags = getStringArrayHelper(data, "tags");
|
||||
info.viewer_count = obs_data_get_int(data, "viewer_count");
|
||||
info.started_at =
|
||||
parseRFC3339Date(obs_data_get_string(data, "started_at"));
|
||||
info.language = obs_data_get_string(data, "language");
|
||||
info.thumbnail_url = obs_data_get_string(data, "thumbnail_url");
|
||||
info.is_mature = obs_data_get_bool(data, "is_mature");
|
||||
return info;
|
||||
}
|
||||
|
||||
std::optional<ChannelInfo> TwitchChannel::GetInfo(const TwitchToken &token)
|
||||
{
|
||||
auto id = GetUserID(token);
|
||||
if (!IsValid(id)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
httplib::Params params = {
|
||||
{"first", "1"}, {"after", ""}, {"broadcaster_id", id}};
|
||||
auto result = SendGetRequest("https://api.twitch.tv", "/helix/channels",
|
||||
token, params, true);
|
||||
if (result.status != 200) {
|
||||
return {};
|
||||
}
|
||||
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(result.data, "data");
|
||||
size_t count = obs_data_array_count(array);
|
||||
if (count == 0) {
|
||||
return {};
|
||||
}
|
||||
OBSDataAutoRelease data = obs_data_array_item(array, 0);
|
||||
|
||||
ChannelInfo info;
|
||||
info.broadcaster_id = obs_data_get_string(data, "broadcaster_id");
|
||||
info.broadcaster_login = obs_data_get_string(data, "broadcaster_login");
|
||||
info.broadcaster_name = obs_data_get_string(data, "broadcaster_name");
|
||||
info.broadcaster_language =
|
||||
obs_data_get_string(data, "broadcaster_language");
|
||||
info.game_name = obs_data_get_string(data, "game_name");
|
||||
info.game_id = obs_data_get_string(data, "game_id");
|
||||
info.title = obs_data_get_string(data, "title");
|
||||
info.delay = obs_data_get_int(data, "delay");
|
||||
info.tags = getStringArrayHelper(data, "tags");
|
||||
info.content_classification_labels =
|
||||
getStringArrayHelper(data, "thumbnail_url");
|
||||
info.is_branded_content = obs_data_get_bool(data, "is_branded_content");
|
||||
return info;
|
||||
}
|
||||
|
||||
bool TwitchChannel::IsValid(const std::string &id) const
|
||||
{
|
||||
return id != "invalid" && !id.empty();
|
||||
}
|
||||
|
||||
TwitchChannelSelection::TwitchChannelSelection(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
_channelName(new VariableLineEdit(this)),
|
||||
_openChannel(new QPushButton(
|
||||
obs_module_text("AdvSceneSwitcher.channel.open")))
|
||||
{
|
||||
QWidget::connect(_channelName, SIGNAL(editingFinished()), this,
|
||||
SLOT(SelectionChanged()));
|
||||
QWidget::connect(_openChannel, SIGNAL(pressed()), this,
|
||||
SLOT(OpenChannel()));
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(_channelName);
|
||||
layout->addWidget(_openChannel);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void TwitchChannelSelection::SetChannel(const TwitchChannel &channel)
|
||||
{
|
||||
_channelName->setText(channel._name);
|
||||
}
|
||||
|
||||
void TwitchChannelSelection::OpenChannel()
|
||||
{
|
||||
// Resolve potential variables
|
||||
StringVariable temp = _channelName->text().toStdString();
|
||||
QDesktopServices::openUrl("https://www.twitch.tv/" +
|
||||
QString::fromStdString(temp));
|
||||
}
|
||||
|
||||
void TwitchChannelSelection::SelectionChanged()
|
||||
{
|
||||
TwitchChannel channel;
|
||||
channel._name = _channelName->text().toStdString();
|
||||
emit ChannelChanged(channel);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
81
src/macro-external/twitch/channel-selection.hpp
Normal file
81
src/macro-external/twitch/channel-selection.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
#include <obs-data.h>
|
||||
#include <variable-line-edit.hpp>
|
||||
#include <QPushButton>
|
||||
#include <QDate>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class TwitchToken;
|
||||
|
||||
// Information returned by the https://api.twitch.tv/helix/streams API call
|
||||
// Channel must be live
|
||||
struct ChannelLiveInfo {
|
||||
bool IsLive() const;
|
||||
|
||||
std::string id;
|
||||
std::string user_id;
|
||||
std::string user_login;
|
||||
std::string user_name;
|
||||
std::string game_id;
|
||||
std::string game_name;
|
||||
std::string type;
|
||||
std::string title;
|
||||
std::vector<std::string> tags;
|
||||
int viewer_count;
|
||||
QDate started_at;
|
||||
std::string language;
|
||||
std::string thumbnail_url;
|
||||
bool is_mature;
|
||||
};
|
||||
|
||||
// Information returned by the https://api.twitch.tv/helix/channels API call
|
||||
// Channel can be offline
|
||||
struct ChannelInfo {
|
||||
std::string broadcaster_id;
|
||||
std::string broadcaster_login;
|
||||
std::string broadcaster_name;
|
||||
std::string broadcaster_language;
|
||||
std::string game_name;
|
||||
std::string game_id;
|
||||
std::string title;
|
||||
uint32_t delay;
|
||||
std::vector<std::string> tags;
|
||||
std::vector<std::string> content_classification_labels;
|
||||
bool is_branded_content;
|
||||
};
|
||||
|
||||
struct TwitchChannel {
|
||||
void Load(obs_data_t *obj);
|
||||
void Save(obs_data_t *obj) const;
|
||||
std::string GetUserID(const TwitchToken &);
|
||||
bool IsValid(const std::string &id) const;
|
||||
std::optional<ChannelLiveInfo> GetLiveInfo(const TwitchToken &);
|
||||
std::optional<ChannelInfo> GetInfo(const TwitchToken &);
|
||||
|
||||
private:
|
||||
StringVariable _name = "";
|
||||
|
||||
friend class TwitchChannelSelection;
|
||||
};
|
||||
|
||||
class TwitchChannelSelection : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TwitchChannelSelection(QWidget *parent);
|
||||
void SetChannel(const TwitchChannel &);
|
||||
|
||||
private slots:
|
||||
void SelectionChanged();
|
||||
void OpenChannel();
|
||||
|
||||
signals:
|
||||
void ChannelChanged(const TwitchChannel &);
|
||||
|
||||
private:
|
||||
VariableLineEdit *_channelName;
|
||||
QPushButton *_openChannel;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
Reference in New Issue
Block a user