Add support for 3rd party service.xconfigs

3rd party service.xconfigs are located in %AppDataPath%/services
(e.g. %APPDATA%/OBS/services in non-portable mode) and have the same
format as a single service definition in services.xconfig without the id
field, e.g.:

"My Service" : {
  servers : {
    Primary : "rtmp://live.example.org/live"
    Secondary : "rtmp://live.example.com/live"
  }
  recommended : {
    "max bitrate" : 1337
  }
}
master
palana 2014-09-11 20:24:51 +02:00
parent 1ec1eb7e24
commit edfbea5ba0
8 changed files with 390 additions and 219 deletions

View File

@ -301,6 +301,7 @@
<ClCompile Include="Source\OBSVideoCapture.cpp" />
<ClCompile Include="Source\RTMPPublisher.cpp" />
<ClCompile Include="Source\RTMPStuff.cpp" />
<ClCompile Include="Source\Service.cpp" />
<ClCompile Include="Source\Settings.cpp" />
<ClCompile Include="Source\SettingsAdvanced.cpp" />
<ClCompile Include="Source\SettingsAudio.cpp" />

View File

@ -160,6 +160,9 @@
<ClCompile Include="Source\SettingsQSV.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="Source\Service.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Source\D3D10System.h">

View File

@ -588,6 +588,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
if(!OSFileExists(strUpdatePath) && !OSCreateDirectory(strUpdatePath))
CrashError(TEXT("Couldn't create directory '%s'"), strUpdatePath.Array());
String servicesPath = strAppDataPath + L"\\services";
if (!OSFileExists(servicesPath) && !OSCreateDirectory(servicesPath))
CrashError(TEXT("Couldn't create directory '%s'"), servicesPath.Array());
LoadGlobalIni();
String strAllocator = GlobalConfig->GetString(TEXT("General"), TEXT("Allocator"));

View File

@ -16,6 +16,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include <functional>
#pragma once
@ -521,6 +522,24 @@ struct StreamInfo
//----------------------------
struct ServiceIdentifier
{
int id;
String file;
ServiceIdentifier(int id, String file) : id(id), file(file) {}
bool operator==(const ServiceIdentifier &sid) { return id == sid.id && file == sid.file; }
bool operator!=(const ServiceIdentifier &sid) { return !(*this == sid); }
};
std::vector<ServiceIdentifier> LoadServiceIdentifiers();
void EnumerateServices(std::function<bool(ServiceIdentifier, XElement*)>);
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(const ServiceIdentifier&, String *failReason=nullptr);
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(String *failReason=nullptr);
ServiceIdentifier GetCurrentService();
//----------------------------
struct StatusBarDrawData
{
UINT bytesPerSec;

View File

@ -830,7 +830,6 @@ DWORD WINAPI RTMPPublisher::CreateConnectionThread(RTMPPublisher *publisher)
String failReason;
String strBindIP;
int serviceID = AppConfig->GetInt (TEXT("Publish"), TEXT("Service"));
String strURL = AppConfig->GetString(TEXT("Publish"), TEXT("URL"));
String strPlayPath = AppConfig->GetString(TEXT("Publish"), TEXT("PlayPath"));
@ -851,6 +850,10 @@ DWORD WINAPI RTMPPublisher::CreateConnectionThread(RTMPPublisher *publisher)
//--------------------------------
ServiceIdentifier sid = GetCurrentService();
//--------------------------------
if(!strURL.IsValid())
{
failReason = TEXT("No server specified to connect to");
@ -858,38 +861,15 @@ DWORD WINAPI RTMPPublisher::CreateConnectionThread(RTMPPublisher *publisher)
}
// A service ID implies the settings have come from the xconfig file.
if(serviceID != 0)
if(sid.id != 0 || sid.file.IsValid())
{
XConfig serverData;
if (!serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
{
failReason = TEXT("Could not open services.xconfig");
goto end;
}
XElement *services = serverData.GetElement(TEXT("services"));
if(!services)
{
failReason = TEXT("Could not find any services in services.xconfig");
goto end;
}
XElement *service = NULL;
DWORD numServices = services->NumElements();
for(UINT i=0; i<numServices; i++)
{
XElement *curService = services->GetElementByID(i);
if(curService->GetInt(TEXT("id")) == serviceID)
{
// Found the service in the xconfig file.
service = curService;
break;
}
}
auto serviceData = LoadService(&failReason);
auto service = serviceData.second;
if(!service)
{
failReason = TEXT("Could not find the service specified in services.xconfig");
if (failReason.IsEmpty())
failReason = TEXT("Could not find the service specified in services.xconfig");
goto end;
}

188
Source/Service.cpp Normal file
View File

@ -0,0 +1,188 @@
/********************************************************************************
Copyright (C) 2014 Ruwen Hahn <palana@stunned.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include "Main.h"
#include <functional>
using namespace std;
static inline void LoadBuiltinServices(vector<ServiceIdentifier> &services_)
{
XConfig serverData;
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
{
XElement *services = serverData.GetElement(TEXT("services"));
if (services)
{
auto numServices = services->NumElements();
for (decltype(numServices) i = 0; i < numServices; i++)
{
auto service = services->GetElementByID(i);
if (!service)
continue;
services_.emplace_back(service->GetInt(L"id"), String());
}
}
}
}
static inline void LoadUserServices(vector<ServiceIdentifier> &services)
{
OSFindData findData;
String servicesDir = FormattedString(L"%s/services/", API->GetAppDataPath());
if (HANDLE find = OSFindFirstFile(FormattedString(L"%s/*.xconfig", servicesDir.Array()), findData))
{
do
{
if (findData.bDirectory)
continue;
XConfig service(servicesDir + findData.fileName);
if (!service.IsOpen())
continue;
services.emplace_back(0, findData.fileName);
} while (OSFindNextFile(find, findData));
OSFindClose(find);
}
}
vector<ServiceIdentifier> LoadServiceIdentifiers()
{
vector<ServiceIdentifier> services;
LoadBuiltinServices(services);
LoadUserServices(services);
return services;
}
static inline bool EnumerateBuiltinServices(function<bool(ServiceIdentifier, XElement*)> &func)
{
XConfig serverData;
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
{
XElement *services = serverData.GetElement(TEXT("services"));
if (services)
{
auto numServices = services->NumElements();
for (decltype(numServices) i = 0; i < numServices; i++)
{
auto service = services->GetElementByID(i);
if (!service)
continue;
if (!func({ service->GetInt(L"id"), String() }, service))
return false;
}
}
}
return true;
}
static inline void EnumerateUserServices(function<bool(ServiceIdentifier, XElement*)> &func)
{
OSFindData findData;
String servicesDir = FormattedString(L"%s/services/", API->GetAppDataPath());
if (HANDLE find = OSFindFirstFile(FormattedString(L"%s/*.xconfig", servicesDir.Array()), findData))
{
do
{
if (findData.bDirectory)
continue;
XConfig service(servicesDir + findData.fileName);
if (!service.IsOpen())
continue;
func({ 0, findData.fileName }, service.GetElementByID(0));
} while (OSFindNextFile(find, findData));
OSFindClose(find);
}
}
void EnumerateServices(function<bool(ServiceIdentifier, XElement*)> func)
{
if (!EnumerateBuiltinServices(func))
return;
EnumerateUserServices(func);
}
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(const ServiceIdentifier& sid, String *failReason)
{
auto fail = [&](CTSTR reason)
{
if (failReason)
*failReason = reason;
return make_pair(std::unique_ptr<XConfig>(), nullptr);
};
auto serverData = make_unique<XConfig>();
if (sid.file.IsEmpty())
{
if (!serverData->Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
return fail(L"Could not open services.xconfig");
XElement *services = serverData->GetElement(TEXT("services"));
if (!services)
return fail(L"Could not find any services in services.xconfig");
XElement *service = NULL;
auto numServices = services->NumElements();
for (decltype(numServices) i = 0; i < numServices; i++)
{
XElement *curService = services->GetElementByID(i);
if (!curService)
continue;
if (curService->GetInt(L"id") == sid.id)
return { move(serverData), curService };
}
}
else
{
if (serverData->Open(FormattedString(L"%s/services/%s", API->GetAppDataPath(), sid.file.Array())))
return { move(serverData), serverData->GetElementByID(sid.id) };
else
return fail(FormattedString(L"Could not open service file '%s'", sid.file.Array()));
}
return make_pair(std::unique_ptr<XConfig>(), nullptr);
}
std::pair<std::unique_ptr<XConfig>, XElement*> LoadService(String *failReason)
{
return LoadService(GetCurrentService(), failReason);
}
ServiceIdentifier GetCurrentService()
{
int serviceID = AppConfig->GetInt(L"Publish", L"Service", 0);
String serviceFile = AppConfig->GetString(L"Publish", L"ServiceFile");
return { serviceID, serviceFile };
}

View File

@ -102,6 +102,7 @@ private:
//-----------------------------------------------------------------------
// Private members
std::vector<ServiceIdentifier> services;
private:
void SetWarningInfo();

View File

@ -21,7 +21,10 @@
#pragma warning(disable: 4530)
#include <vector>
#include <unordered_map>
#include <string>
#include <functional>
#include <algorithm>
//============================================================================
// Helpers
@ -109,10 +112,11 @@ void SettingsPublish::ApplySettings()
AppConfig->SetInt(TEXT("Publish"), TEXT("Mode"), curSel);
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0);
if(serviceID != CB_ERR)
if(serviceID != CB_ERR && serviceID >= 0 && serviceID < (int)services.size())
{
serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, serviceID, 0);
AppConfig->SetInt(TEXT("Publish"), TEXT("Service"), serviceID);
auto sid = services[serviceID];
AppConfig->SetInt(TEXT("Publish"), TEXT("Service"), sid.id);
AppConfig->SetString(L"Publish", L"ServiceFile", sid.file);
}
String strTemp = GetEditText(GetDlgItem(hwnd, IDC_PLAYPATH));
@ -198,7 +202,7 @@ bool SettingsPublish::HasDefaults() const
void SettingsPublish::SetWarningInfo()
{
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0);
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0);
bool bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0;
int maxBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000);
@ -219,135 +223,127 @@ void SettingsPublish::SetWarningInfo()
bool canOptimize = false;
String strWarnings;
XConfig serverData;
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
if (serviceID >= 0 && serviceID < (int)services.size())
{
XElement *services = serverData.GetElement(TEXT("services"));
if(services)
auto serviceData = LoadService(services[serviceID]);
auto service = serviceData.second;
if (service)
{
UINT numServices = services->NumElements();
for(UINT i=0; i<numServices; i++)
if (service->GetInt(TEXT("id")) == serviceID)
{
XElement *service = services->GetElementByID(i);
if (service->GetInt(TEXT("id")) == serviceID)
strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName());
//check to see if the service we're using has recommendations
if (!service->HasItem(TEXT("recommended")))
{
strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName());
SetDlgItemText(hwnd, IDC_WARNINGS, TEXT(""));
return;
}
//check to see if the service we're using has recommendations
if (!service->HasItem(TEXT("recommended")))
XElement *r = service->GetElement(TEXT("recommended"));
if (r->HasItem(TEXT("ratecontrol")))
{
CTSTR rc = r->GetString(TEXT("ratecontrol"));
if (!scmp(rc, TEXT("cbr")) && !bUseCBR)
{
SetDlgItemText(hwnd, IDC_WARNINGS, TEXT(""));
return;
hasErrors = true;
canOptimize = true;
strWarnings << Str("Settings.Publish.Warning.UseCBR");
}
}
XElement *r = service->GetElement(TEXT("recommended"));
if (r->HasItem(TEXT("ratecontrol")))
if (r->HasItem(TEXT("max bitrate")))
{
int max_bitrate = r->GetInt(TEXT("max bitrate"));
if (maxBitRate > max_bitrate)
{
CTSTR rc = r->GetString(TEXT("ratecontrol"));
if (!scmp (rc, TEXT("cbr")) && !bUseCBR)
{
hasErrors = true;
canOptimize = true;
strWarnings << Str("Settings.Publish.Warning.UseCBR");
}
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate);
}
}
if (r->HasItem(TEXT("max bitrate")))
if (r->HasItem(L"supported audio codec"))
{
StringList codecs;
r->GetStringList(L"supported audio codec", codecs);
if (codecs.FindValueIndex(currentAudioCodec) == INVALID)
{
int max_bitrate = r->GetInt(TEXT("max bitrate"));
if (maxBitRate > max_bitrate)
{
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate);
}
String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution
msg.FindReplace(L"$1", codecs[0].Array());
msg.FindReplace(L"$2", currentAudioCodec.Array());
hasErrors = true;
canOptimize = true;
strWarnings << msg;
}
}
if (r->HasItem(L"supported audio codec"))
if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC"))))
{
int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac"));
if (audioBitRate > maxaudioaac)
{
StringList codecs;
r->GetStringList(L"supported audio codec", codecs);
if (codecs.FindValueIndex(currentAudioCodec) == INVALID)
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac);
}
}
if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3"))))
{
int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3"));
if (audioBitRate > maxaudiomp3)
{
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3);
}
}
if (r->HasItem(L"video aspect ratio"))
{
String aspectRatio = r->GetString(L"video aspect ratio");
StringList numbers;
aspectRatio.GetTokenList(numbers, ':');
if (numbers.Num() == 2)
{
float aspect = numbers[0].ToInt() / max(1.f, numbers[1].ToFloat());
if (!CloseFloat(aspect, currentAspect))
{
String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution
msg.FindReplace(L"$1", codecs[0].Array());
msg.FindReplace(L"$2", currentAudioCodec.Array());
hasErrors = true;
canOptimize = true;
String aspectLocalized = Str("Settings.Video.AspectRatioFormat");
aspectLocalized.FindReplace(L"$1", UIntString(numbers[0].ToInt()));
aspectLocalized.FindReplace(L"$2", UIntString(numbers[1].ToInt()));
String msg = Str("Settings.Publish.Warning.VideoAspectRatio");
msg.FindReplace(L"$1", aspectLocalized);
strWarnings << msg;
}
}
if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC"))))
{
int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac"));
if (audioBitRate > maxaudioaac)
{
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac);
}
}
}
if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3"))))
if (r->HasItem(TEXT("profile")))
{
String expectedProfile = r->GetString(TEXT("profile"));
if (!expectedProfile.CompareI(currentx264Profile))
{
int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3"));
if (audioBitRate > maxaudiomp3)
{
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3);
}
hasErrors = true;
canOptimize = true;
strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile");
}
}
if (r->HasItem(L"video aspect ratio"))
if (r->HasItem(TEXT("keyint")))
{
int keyint = r->GetInt(TEXT("keyint"));
if (!keyframeInt || keyframeInt * 1000 > keyint)
{
String aspectRatio = r->GetString(L"video aspect ratio");
StringList numbers;
aspectRatio.GetTokenList(numbers, ':');
if (numbers.Num() == 2)
{
float aspect = numbers[0].ToInt() / max(1.f, numbers[1].ToFloat());
if (!CloseFloat(aspect, currentAspect))
{
String aspectLocalized = Str("Settings.Video.AspectRatioFormat");
aspectLocalized.FindReplace(L"$1", UIntString(numbers[0].ToInt()));
aspectLocalized.FindReplace(L"$2", UIntString(numbers[1].ToInt()));
String msg = Str("Settings.Publish.Warning.VideoAspectRatio");
msg.FindReplace(L"$1", aspectLocalized);
strWarnings << msg;
hasErrors = true;
}
}
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000);
}
if (r->HasItem(TEXT("profile")))
{
String expectedProfile = r->GetString(TEXT("profile"));
if (!expectedProfile.CompareI(currentx264Profile))
{
hasErrors = true;
canOptimize = true;
strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile");
}
}
if (r->HasItem(TEXT("keyint")))
{
int keyint = r->GetInt(TEXT("keyint"));
if (!keyframeInt || keyframeInt * 1000 > keyint)
{
hasErrors = true;
canOptimize = true;
strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000);
}
}
break;
}
}
}
@ -390,32 +386,21 @@ static void UpdateMemoryUsage(HWND hwnd)
void SettingsPublish::OptimizeSettings()
{
auto refresh_on_exit = GuardScope([&] { SetWarningInfo(); UpdateMemoryUsage(hwnd); });
XConfig serverData;
if (!serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0);
if (serviceID < 0 || serviceID >= (int)services.size())
return;
XElement *services = serverData.GetElement(L"services");
if (!services)
auto serviceData = LoadService(services[serviceID]);
auto service = serviceData.second;
if (!service)
return;
//check to see if the service we're using has recommendations
if (!service->HasItem(L"recommended"))
return;
UINT numServices = services->NumElements();
int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0);
XElement *r = nullptr;
for (UINT i = 0; i < numServices; i++)
{
XElement *service = services->GetElementByID(i);
if (service->GetInt(L"id") != serviceID)
continue;
//check to see if the service we're using has recommendations
if (!service->HasItem(L"recommended"))
return;
r = service->GetElement(L"recommended");
break;
}
XElement *r = service->GetElement(L"recommended");
if (!r)
return;
@ -544,27 +529,53 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
hwndTemp = GetDlgItem(hwnd, IDC_SERVICE);
int itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("Custom"));
SendMessage(hwndTemp, CB_SETITEMDATA, itemId, 0);
services.emplace_back(0, String());
UINT numServices = 0;
XConfig serverData;
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
ServiceIdentifier current = GetCurrentService();
std::unordered_map<std::wstring, int> duplicates;
EnumerateServices([&](ServiceIdentifier sid, XElement *service)
{
XElement *services = serverData.GetElement(TEXT("services"));
if(services)
services.emplace_back(sid);
auto pos = duplicates.find(service->GetName());
int id;
if (pos != end(duplicates))
{
numServices = services->NumElements();
for(UINT i=0; i<numServices; i++)
const ServiceIdentifier &first = services[pos->second];
if (first.file.IsValid())
{
XElement *service = services->GetElementByID(i);
itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)service->GetName());
SendMessage(hwndTemp, CB_SETITEMDATA, itemId, service->GetInt(TEXT("id")));
SendMessage(hwndTemp, CB_DELETESTRING, pos->second, 0);
SendMessage(hwndTemp, CB_INSERTSTRING, pos->second, (LPARAM)FormattedString(L"%s [%s]", service->GetName(), services[pos->second].file.Array()).Array());
}
id = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)(sid.file.IsValid() ? FormattedString(L"%s [%s]", service->GetName(), sid.file.Array()).Array() : service->GetName()));
}
else
{
id = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)service->GetName());
duplicates[service->GetName()] = id;
}
}
int serviceID = AppConfig->GetInt(TEXT("Publish"), TEXT("Service"), 0);
[&]()
{
if (sid != current)
return;
SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, id, 0);
XElement *servers = service->GetElement(L"servers");
if (!servers)
return;
UINT numServers = servers->NumDataItems();
for (UINT i = 0; i < numServers; i++)
{
XDataItem *server = servers->GetDataItemByID(i);
SendMessage(GetDlgItem(hwnd, IDC_SERVERLIST), CB_ADDSTRING, 0, (LPARAM)server->GetName());
}
}();
return true;
});
if(mode != 0) ShowWindow(hwndTemp, SW_HIDE);
@ -574,7 +585,7 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
LoadSettingEditString(hwndTemp, TEXT("Publish"), TEXT("PlayPath"), NULL);
if(mode != 0) ShowWindow(hwndTemp, SW_HIDE);
if(serviceID == 0) //custom
if(current.file.IsEmpty() && current.id == 0) //custom
{
ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE);
hwndTemp = GetDlgItem(hwnd, IDC_URL);
@ -585,38 +596,6 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE);
hwndTemp = GetDlgItem(hwnd, IDC_SERVERLIST);
XElement *services = serverData.GetElement(TEXT("services"));
if(services)
{
XElement *service = NULL;
numServices = services->NumElements();
for(UINT i=0; i<numServices; i++)
{
XElement *curService = services->GetElementByID(i);
if(curService->GetInt(TEXT("id")) == serviceID)
{
SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, i+1, 0);
service = curService;
break;
}
}
if(service)
{
XElement *servers = service->GetElement(TEXT("servers"));
if(servers)
{
UINT numServers = servers->NumDataItems();
for(UINT i=0; i<numServers; i++)
{
XDataItem *server = servers->GetDataItemByID(i);
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName());
}
}
}
}
LoadSettingComboString(hwndTemp, TEXT("Publish"), TEXT("URL"), NULL);
}
@ -937,24 +916,20 @@ INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam)
ShowWindow(hwndTemp, SW_SHOW);
SendMessage(hwndTemp, CB_RESETCONTENT, 0, 0);
XConfig serverData;
if (serverData.Open(FormattedString(L"%s\\services.xconfig", API->GetAppPath())))
if (serviceID >= 0 && serviceID < (int)services.size())
{
XElement *services = serverData.GetElement(TEXT("services"));
if(services)
auto serviceData = LoadService(services[serviceID]);
auto service = serviceData.second;
if (service)
{
XElement *service = services->GetElementByID(serviceID-1);
if(service)
XElement *servers = service->GetElement(TEXT("servers"));
if (servers)
{
XElement *servers = service->GetElement(TEXT("servers"));
if(servers)
UINT numServers = servers->NumDataItems();
for (UINT i = 0; i < numServers; i++)
{
UINT numServers = servers->NumDataItems();
for(UINT i=0; i<numServers; i++)
{
XDataItem *server = servers->GetDataItemByID(i);
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName());
}
XDataItem *server = servers->GetDataItemByID(i);
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName());
}
}
}