diff options
64 files changed, 6790 insertions, 6731 deletions
@@ -1,127 +1,130 @@ #include "Config.h" -const char* Config::viewModeNames[] -{ - "Cover", - "List", - "Detail" -}; +const char *Config::viewModeNames[] + { + "Cover", + "List", + "Detail" + }; Config::Config() { - s_username = "username"; - s_password = "password"; - CoverGridColumns = 7; - CoverGridRows = 2; - ListGridColumns = 1; - ListGridRows = 12; - DetailGridColumns = 1; - DetailGridRows = 4; - ExtrasGridColumns = 4; - ExtrasGridRows = 1; - - UseMpv = false; - UseAc3 = true; - ScrollByPage = true; - ScrollAllAround = true; - BufferSize = 1; - - DefaultViewMode = ViewMode::Cover; - - ViewEntry en; - en.Name = "Recently Added"; - en.PlexPath = "/library/recentlyAdded"; - m_viewentries.push_back(en); - - ViewEntry en2; - en2.Name = "On Deck"; - en2.PlexPath = "/library/onDeck"; - m_viewentries.push_back(en2); - - ViewEntry en3; - en3.Name = "Library"; - en3.PlexPath = "/library/sections"; - m_serverViewentries.push_back(en3); - - ViewEntry en4; - en4.Name = "Video Channels"; - en4.PlexPath = "/video"; - m_serverViewentries.push_back(en4); - + s_username = "username"; + s_password = "password"; + CoverGridColumns = 7; + CoverGridRows = 2; + ListGridColumns = 1; + ListGridRows = 12; + DetailGridColumns = 1; + DetailGridRows = 4; + ExtrasGridColumns = 4; + ExtrasGridRows = 1; + + UseMpv = false; + UseAc3 = true; + ScrollByPage = true; + ScrollAllAround = true; + BufferSize = 1; + + DefaultViewMode = ViewMode::Cover; + + ViewEntry en; + en.Name = "Recently Added"; + en.PlexPath = "/library/recentlyAdded"; + m_viewentries.push_back(en); + + ViewEntry en2; + en2.Name = "On Deck"; + en2.PlexPath = "/library/onDeck"; + m_viewentries.push_back(en2); + + ViewEntry en3; + en3.Name = "Library"; + en3.PlexPath = "/library/sections"; + m_serverViewentries.push_back(en3); + + ViewEntry en4; + en4.Name = "Video Channels"; + en4.PlexPath = "/video"; + m_serverViewentries.push_back(en4); + } std::string Config::GetUUID() { - if(s_uuid.empty()) { - using Poco::UUIDGenerator; - using Poco::UUID; - UUIDGenerator &generator = UUIDGenerator::defaultGenerator(); - UUID uuid(generator.createRandom()); - s_uuid = uuid.toString(); - } - return s_uuid; + if (s_uuid.empty()) { + using Poco::UUIDGenerator; + using Poco::UUID; + UUIDGenerator &generator = UUIDGenerator::defaultGenerator(); + UUID uuid(generator.createRandom()); + s_uuid = uuid.toString(); + } + return s_uuid; } -void Config::SetUUID(const char* uuid) { - if (uuid) s_uuid = std::string(uuid); +void Config::SetUUID(const char *uuid) { + if (uuid) s_uuid = std::string(uuid); } std::string Config::GetHostname() { - if(s_hostname.empty()) { - char hostname[1024]; - gethostname(hostname, 1024); - s_hostname = std::string(hostname); - } - return s_hostname; + if (s_hostname.empty()) { + char hostname[1024]; + gethostname(hostname, 1024); + s_hostname = std::string(hostname); + } + return s_hostname; } std::string Config::GetLanguage() { - return "de"; + return "de"; } std::string Config::GetUsername() { - return s_username; + return s_username; } std::string Config::GetPassword() { - return s_password; + return s_password; } -bool Config::Parse(const char *name, const char *value) -{ - //dsyslog("[plex]%s: '%s' = '%s'\n", __FUNCTION__, name, value); - bool parsed = true; - if (strcasecmp(name, "HideMainMenuEntry") == 0) Config::GetInstance().HideMainMenuEntry = atoi(value) ? true : false; - else if (strcasecmp(name, "UsePlexAccount") == 0) Config::GetInstance().UsePlexAccount = atoi(value) ? true : false; - else if (strcasecmp(name, "UseCustomTranscodeProfile") == 0) Config::GetInstance().UseCustomTranscodeProfile = atoi(value) ? true : false; - else if (strcasecmp(name, "Username") == 0) Config::GetInstance().s_username = std::string(value); - else if (strcasecmp(name, "Password") == 0) Config::GetInstance().s_password = std::string(value); - else if (strcasecmp(name, "UUID") == 0) Config::GetInstance().SetUUID(value); - else if (strcasecmp(name, "UseConfiguredServer") == 0) Config::GetInstance().UseConfiguredServer = atoi(value) ? true : false; - else if (strcasecmp(name, "ServerHost") == 0) Config::GetInstance().s_serverHost = std::string(value); - else if (strcasecmp(name, "ServerPort") == 0) Config::GetInstance().ServerPort = atoi(value); - else if (strcasecmp(name, "CoverGridColumns") == 0) Config::GetInstance().CoverGridColumns = atoi(value); - else if (strcasecmp(name, "CoverGridRows") == 0) Config::GetInstance().CoverGridRows = atoi(value); - else if (strcasecmp(name, "DetailGridColumns") == 0) Config::GetInstance().DetailGridColumns = atoi(value); - else if (strcasecmp(name, "DetailGridRows") == 0) Config::GetInstance().DetailGridRows = atoi(value); - else if (strcasecmp(name, "ListGridColumns") == 0) Config::GetInstance().ListGridColumns = atoi(value); - else if (strcasecmp(name, "ListGridRows") == 0) Config::GetInstance().ListGridRows = atoi(value); - else if (strcasecmp(name, "ExtrasGridColumns") == 0) Config::GetInstance().ExtrasGridColumns = atoi(value); - else if (strcasecmp(name, "ExtrasGridRows") == 0) Config::GetInstance().ExtrasGridRows = atoi(value); - else if (strcasecmp(name, "UseMpv") == 0) Config::GetInstance().UseMpv = atoi(value) ? true : false; - else if (strcasecmp(name, "ScrollByPage") == 0) Config::GetInstance().ScrollByPage = atoi(value) ? true : false; - else if (strcasecmp(name, "ScrollAllAround") == 0) Config::GetInstance().ScrollAllAround = atoi(value) ? true : false; - else if (strcasecmp(name, "UseAc3") == 0) Config::GetInstance().UseAc3 = atoi(value) ? true : false; - else if (strcasecmp(name, "BufferSize") == 0) Config::GetInstance().BufferSize = atoi(value); - else parsed = false; - - if(!parsed) { - // Parse ViewEntries - - } - - return parsed; +bool Config::Parse(const char *name, const char *value) { + //dsyslog("[plex]%s: '%s' = '%s'\n", __FUNCTION__, name, value); + bool parsed = true; + if (strcasecmp(name, "HideMainMenuEntry") == 0) + Config::GetInstance().HideMainMenuEntry = atoi(value) ? true : false; + else if (strcasecmp(name, "UsePlexAccount") == 0) Config::GetInstance().UsePlexAccount = atoi(value) ? true : false; + else if (strcasecmp(name, "UseCustomTranscodeProfile") == 0) + Config::GetInstance().UseCustomTranscodeProfile = atoi(value) ? true : false; + else if (strcasecmp(name, "Username") == 0) Config::GetInstance().s_username = std::string(value); + else if (strcasecmp(name, "Password") == 0) Config::GetInstance().s_password = std::string(value); + else if (strcasecmp(name, "UUID") == 0) Config::GetInstance().SetUUID(value); + else if (strcasecmp(name, "UseConfiguredServer") == 0) + Config::GetInstance().UseConfiguredServer = atoi(value) ? true : false; + else if (strcasecmp(name, "ServerHost") == 0) Config::GetInstance().s_serverHost = std::string(value); + else if (strcasecmp(name, "ServerPort") == 0) Config::GetInstance().ServerPort = atoi(value); + else if (strcasecmp(name, "CoverGridColumns") == 0) Config::GetInstance().CoverGridColumns = atoi(value); + else if (strcasecmp(name, "CoverGridRows") == 0) Config::GetInstance().CoverGridRows = atoi(value); + else if (strcasecmp(name, "DetailGridColumns") == 0) Config::GetInstance().DetailGridColumns = atoi(value); + else if (strcasecmp(name, "DetailGridRows") == 0) Config::GetInstance().DetailGridRows = atoi(value); + else if (strcasecmp(name, "ListGridColumns") == 0) Config::GetInstance().ListGridColumns = atoi(value); + else if (strcasecmp(name, "ListGridRows") == 0) Config::GetInstance().ListGridRows = atoi(value); + else if (strcasecmp(name, "ExtrasGridColumns") == 0) Config::GetInstance().ExtrasGridColumns = atoi(value); + else if (strcasecmp(name, "ExtrasGridRows") == 0) Config::GetInstance().ExtrasGridRows = atoi(value); + else if (strcasecmp(name, "UseMpv") == 0) Config::GetInstance().UseMpv = atoi(value) ? true : false; + else if (strcasecmp(name, "ScrollByPage") == 0) Config::GetInstance().ScrollByPage = atoi(value) ? true : false; + else if (strcasecmp(name, "ScrollAllAround") == 0) + Config::GetInstance().ScrollAllAround = atoi(value) ? true : false; + else if (strcasecmp(name, "UseAc3") == 0) Config::GetInstance().UseAc3 = atoi(value) ? true : false; + else if (strcasecmp(name, "BufferSize") == 0) Config::GetInstance().BufferSize = atoi(value); + else parsed = false; + + if (!parsed) { + // Parse ViewEntries + + } + + return parsed; } @@ -132,9 +135,8 @@ bool Config::Parse(const char *name, const char *value) /** ** Process key for setup menu. */ -eOSState cMyMenuSetupPage::ProcessKey(eKeys key) -{ - return cMenuSetupPage::ProcessKey(key); +eOSState cMyMenuSetupPage::ProcessKey(eKeys key) { + return cMenuSetupPage::ProcessKey(key); } /** @@ -142,117 +144,116 @@ eOSState cMyMenuSetupPage::ProcessKey(eKeys key) ** ** Import global config variables into setup. */ -cMyMenuSetupPage::cMyMenuSetupPage(void) -{ - strn0cpy(Username, Config::GetInstance().s_username.c_str(), STRING_SIZE); - strn0cpy(Password, Config::GetInstance().s_password.c_str(), STRING_SIZE); - strn0cpy(Uuid, Config::GetInstance().GetUUID().c_str(), STRING_SIZE); - strn0cpy(ServerHost, Config::GetInstance().s_serverHost.c_str(), STRING_SIZE); - ServerPort = Config::GetInstance().ServerPort; - UseConfiguredServer = Config::GetInstance().UseConfiguredServer; - HideMainMenuEntry = Config::GetInstance().HideMainMenuEntry; - UseCustomTranscodeProfile = Config::GetInstance().UseCustomTranscodeProfile; - UsePlexAccount = Config::GetInstance().UsePlexAccount; - CoverGridColumns = Config::GetInstance().CoverGridColumns; - CoverGridRows = Config::GetInstance().CoverGridRows; - DetailGridColumns = Config::GetInstance().DetailGridColumns; - DetailGridRows = Config::GetInstance().DetailGridRows; - ListGridColumns = Config::GetInstance().ListGridColumns; - ListGridRows = Config::GetInstance().ListGridRows; - ExtrasGridColumns = Config::GetInstance().ExtrasGridColumns; - ExtrasGridRows = Config::GetInstance().ExtrasGridRows; - UseMpv = Config::GetInstance().UseMpv; - ScrollByPage = Config::GetInstance().ScrollByPage; - ScrollAllAround = Config::GetInstance().ScrollAllAround; - DefaultViewMode = Config::GetInstance().DefaultViewMode; - UseAc3 = Config::GetInstance().UseAc3; - BufferSize = Config::GetInstance().BufferSize; - - - Add(new cMenuEditBoolItem(tr("Hide main menu entry"), (int*)&HideMainMenuEntry, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditBoolItem(tr("Use AC3 instead of aac Audio"), (int*)&UseAc3, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditBoolItem(tr("Use Mpv Plugin (If Availiable)"), (int*)&UseMpv, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditIntItem(tr("Buffer size for playing, in MB"), &BufferSize, 1, 128)); - - Add(new cMenuEditBoolItem(tr("Scroll by Page"), (int*)&ScrollByPage, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditBoolItem(tr("Scroll all around"), (int*)&ScrollAllAround, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditBoolItem(tr("Use custom transcoding profile"), (int*)&UseCustomTranscodeProfile, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditBoolItem(tr("Use Plex account"), (int*)&UsePlexAccount, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditStrItem(tr("Plex Username"), Username, STRING_SIZE)); - Add(new cMenuEditStrItem(tr("Plex Password"), Password, STRING_SIZE)); - - Add(new cMenuEditBoolItem(tr("Use Custom Server"), (int*)&UseConfiguredServer, trVDR("no"), trVDR("yes"))); - Add(new cMenuEditStrItem(tr("Server Host"), ServerHost, STRING_SIZE)); - Add(new cMenuEditIntItem(tr("Server Port"), &ServerPort)); - - Add(new cMenuEditStraItem(tr("Default View Mode"), &DefaultViewMode, 3, Config::viewModeNames)); - - Add(new cMenuEditIntItem(tr("Cover Grid Columns"), &CoverGridColumns)); - Add(new cMenuEditIntItem(tr("Cover Grid Rows"), &CoverGridRows)); - - Add(new cMenuEditIntItem(tr("Detail Grid Columns"), &DetailGridColumns)); - Add(new cMenuEditIntItem(tr("Detail Grid Rows"), &DetailGridRows)); - - Add(new cMenuEditIntItem(tr("List Grid Columns"), &ListGridColumns)); - Add(new cMenuEditIntItem(tr("List Grid Rows"), &ListGridRows)); - - Add(new cMenuEditIntItem(tr("Extras Grid Columns"), &ExtrasGridColumns)); - Add(new cMenuEditIntItem(tr("Extras Grid Rows"), &ExtrasGridRows)); - - cMenuEditStrItem* devUUID = new cMenuEditStrItem(tr("Current UUID"), Uuid, STRING_SIZE); - devUUID->SetSelectable(false); - Add(devUUID); +cMyMenuSetupPage::cMyMenuSetupPage(void) { + strn0cpy(Username, Config::GetInstance().s_username.c_str(), STRING_SIZE); + strn0cpy(Password, Config::GetInstance().s_password.c_str(), STRING_SIZE); + strn0cpy(Uuid, Config::GetInstance().GetUUID().c_str(), STRING_SIZE); + strn0cpy(ServerHost, Config::GetInstance().s_serverHost.c_str(), STRING_SIZE); + ServerPort = Config::GetInstance().ServerPort; + UseConfiguredServer = Config::GetInstance().UseConfiguredServer; + HideMainMenuEntry = Config::GetInstance().HideMainMenuEntry; + UseCustomTranscodeProfile = Config::GetInstance().UseCustomTranscodeProfile; + UsePlexAccount = Config::GetInstance().UsePlexAccount; + CoverGridColumns = Config::GetInstance().CoverGridColumns; + CoverGridRows = Config::GetInstance().CoverGridRows; + DetailGridColumns = Config::GetInstance().DetailGridColumns; + DetailGridRows = Config::GetInstance().DetailGridRows; + ListGridColumns = Config::GetInstance().ListGridColumns; + ListGridRows = Config::GetInstance().ListGridRows; + ExtrasGridColumns = Config::GetInstance().ExtrasGridColumns; + ExtrasGridRows = Config::GetInstance().ExtrasGridRows; + UseMpv = Config::GetInstance().UseMpv; + ScrollByPage = Config::GetInstance().ScrollByPage; + ScrollAllAround = Config::GetInstance().ScrollAllAround; + DefaultViewMode = Config::GetInstance().DefaultViewMode; + UseAc3 = Config::GetInstance().UseAc3; + BufferSize = Config::GetInstance().BufferSize; + + + Add(new cMenuEditBoolItem(tr("Hide main menu entry"), (int *) &HideMainMenuEntry, trVDR("no"), trVDR("yes"))); + Add(new cMenuEditBoolItem(tr("Use AC3 instead of aac Audio"), (int *) &UseAc3, trVDR("no"), trVDR("yes"))); + Add(new cMenuEditBoolItem(tr("Use Mpv Plugin (If Availiable)"), (int *) &UseMpv, trVDR("no"), trVDR("yes"))); + Add(new cMenuEditIntItem(tr("Buffer size for playing, in MB"), &BufferSize, 1, 128)); + + Add(new cMenuEditBoolItem(tr("Scroll by Page"), (int *) &ScrollByPage, trVDR("no"), trVDR("yes"))); + Add(new cMenuEditBoolItem(tr("Scroll all around"), (int *) &ScrollAllAround, trVDR("no"), trVDR("yes"))); + Add(new cMenuEditBoolItem(tr("Use custom transcoding profile"), (int *) &UseCustomTranscodeProfile, trVDR("no"), + trVDR("yes"))); + Add(new cMenuEditBoolItem(tr("Use Plex account"), (int *) &UsePlexAccount, trVDR("no"), trVDR("yes"))); + Add(new cMenuEditStrItem(tr("Plex Username"), Username, STRING_SIZE)); + Add(new cMenuEditStrItem(tr("Plex Password"), Password, STRING_SIZE)); + + Add(new cMenuEditBoolItem(tr("Use Custom Server"), (int *) &UseConfiguredServer, trVDR("no"), trVDR("yes"))); + Add(new cMenuEditStrItem(tr("Server Host"), ServerHost, STRING_SIZE)); + Add(new cMenuEditIntItem(tr("Server Port"), &ServerPort)); + + Add(new cMenuEditStraItem(tr("Default View Mode"), &DefaultViewMode, 3, Config::viewModeNames)); + + Add(new cMenuEditIntItem(tr("Cover Grid Columns"), &CoverGridColumns)); + Add(new cMenuEditIntItem(tr("Cover Grid Rows"), &CoverGridRows)); + + Add(new cMenuEditIntItem(tr("Detail Grid Columns"), &DetailGridColumns)); + Add(new cMenuEditIntItem(tr("Detail Grid Rows"), &DetailGridRows)); + + Add(new cMenuEditIntItem(tr("List Grid Columns"), &ListGridColumns)); + Add(new cMenuEditIntItem(tr("List Grid Rows"), &ListGridRows)); + + Add(new cMenuEditIntItem(tr("Extras Grid Columns"), &ExtrasGridColumns)); + Add(new cMenuEditIntItem(tr("Extras Grid Rows"), &ExtrasGridRows)); + + cMenuEditStrItem *devUUID = new cMenuEditStrItem(tr("Current UUID"), Uuid, STRING_SIZE); + devUUID->SetSelectable(false); + Add(devUUID); } /** ** Store setup. */ -void cMyMenuSetupPage::Store(void) -{ - Config::GetInstance().s_username = std::string(Username); - Config::GetInstance().s_password = std::string(Password); - Config::GetInstance().HideMainMenuEntry = HideMainMenuEntry; - Config::GetInstance().UseCustomTranscodeProfile = UseCustomTranscodeProfile; - Config::GetInstance().UsePlexAccount = UsePlexAccount; - Config::GetInstance().UseConfiguredServer = UseConfiguredServer; - Config::GetInstance().s_serverHost = std::string(ServerHost); - Config::GetInstance().ServerPort = ServerPort; - Config::GetInstance().CoverGridColumns = CoverGridColumns; - Config::GetInstance().CoverGridRows = CoverGridRows; - Config::GetInstance().DetailGridColumns = DetailGridColumns; - Config::GetInstance().DetailGridRows = DetailGridRows; - Config::GetInstance().ListGridColumns = ListGridColumns; - Config::GetInstance().ListGridRows = ListGridRows; - Config::GetInstance().ExtrasGridColumns = ExtrasGridColumns; - Config::GetInstance().ExtrasGridRows = ExtrasGridRows; - Config::GetInstance().DefaultViewMode = (ViewMode)DefaultViewMode; - Config::GetInstance().UseMpv = UseMpv; - Config::GetInstance().ScrollByPage = ScrollByPage; - Config::GetInstance().ScrollAllAround = ScrollAllAround; - Config::GetInstance().UseAc3 = UseAc3; - Config::GetInstance().BufferSize = BufferSize; - - SetupStore("UseCustomTranscodeProfile", Config::GetInstance().UseCustomTranscodeProfile); - SetupStore("HideMainMenuEntry", Config::GetInstance().HideMainMenuEntry); - SetupStore("UsePlexAccount", Config::GetInstance().UsePlexAccount); - SetupStore("Username", Config::GetInstance().s_username.c_str()); - SetupStore("Password", Config::GetInstance().s_password.c_str()); - SetupStore("UUID", Config::GetInstance().GetUUID().c_str()); - SetupStore("UseConfiguredServer", Config::GetInstance().UseConfiguredServer); - SetupStore("ServerHost", Config::GetInstance().s_serverHost.c_str()); - SetupStore("ServerPort", Config::GetInstance().ServerPort); - SetupStore("CoverGridColumns", Config::GetInstance().CoverGridColumns); - SetupStore("CoverGridRows", Config::GetInstance().CoverGridRows); - SetupStore("DetailGridColumns", Config::GetInstance().DetailGridColumns); - SetupStore("DetailGridRows", Config::GetInstance().DetailGridRows); - SetupStore("ListGridColumns", Config::GetInstance().ListGridColumns); - SetupStore("ListGridRows", Config::GetInstance().ListGridRows); - SetupStore("ExtrasGridColumns", Config::GetInstance().ExtrasGridColumns); - SetupStore("ExtrasGridRows", Config::GetInstance().ExtrasGridRows); - SetupStore("DefaultViewMode", Config::GetInstance().DefaultViewMode); - SetupStore("UseMpv", Config::GetInstance().UseMpv); - SetupStore("ScrollByPage", Config::GetInstance().ScrollByPage); - SetupStore("ScrollAllAround", Config::GetInstance().ScrollAllAround); - SetupStore("UseAc3", Config::GetInstance().ScrollAllAround); - SetupStore("BufferSize", Config::GetInstance().BufferSize); +void cMyMenuSetupPage::Store(void) { + Config::GetInstance().s_username = std::string(Username); + Config::GetInstance().s_password = std::string(Password); + Config::GetInstance().HideMainMenuEntry = HideMainMenuEntry; + Config::GetInstance().UseCustomTranscodeProfile = UseCustomTranscodeProfile; + Config::GetInstance().UsePlexAccount = UsePlexAccount; + Config::GetInstance().UseConfiguredServer = UseConfiguredServer; + Config::GetInstance().s_serverHost = std::string(ServerHost); + Config::GetInstance().ServerPort = ServerPort; + Config::GetInstance().CoverGridColumns = CoverGridColumns; + Config::GetInstance().CoverGridRows = CoverGridRows; + Config::GetInstance().DetailGridColumns = DetailGridColumns; + Config::GetInstance().DetailGridRows = DetailGridRows; + Config::GetInstance().ListGridColumns = ListGridColumns; + Config::GetInstance().ListGridRows = ListGridRows; + Config::GetInstance().ExtrasGridColumns = ExtrasGridColumns; + Config::GetInstance().ExtrasGridRows = ExtrasGridRows; + Config::GetInstance().DefaultViewMode = (ViewMode) DefaultViewMode; + Config::GetInstance().UseMpv = UseMpv; + Config::GetInstance().ScrollByPage = ScrollByPage; + Config::GetInstance().ScrollAllAround = ScrollAllAround; + Config::GetInstance().UseAc3 = UseAc3; + Config::GetInstance().BufferSize = BufferSize; + + SetupStore("UseCustomTranscodeProfile", Config::GetInstance().UseCustomTranscodeProfile); + SetupStore("HideMainMenuEntry", Config::GetInstance().HideMainMenuEntry); + SetupStore("UsePlexAccount", Config::GetInstance().UsePlexAccount); + SetupStore("Username", Config::GetInstance().s_username.c_str()); + SetupStore("Password", Config::GetInstance().s_password.c_str()); + SetupStore("UUID", Config::GetInstance().GetUUID().c_str()); + SetupStore("UseConfiguredServer", Config::GetInstance().UseConfiguredServer); + SetupStore("ServerHost", Config::GetInstance().s_serverHost.c_str()); + SetupStore("ServerPort", Config::GetInstance().ServerPort); + SetupStore("CoverGridColumns", Config::GetInstance().CoverGridColumns); + SetupStore("CoverGridRows", Config::GetInstance().CoverGridRows); + SetupStore("DetailGridColumns", Config::GetInstance().DetailGridColumns); + SetupStore("DetailGridRows", Config::GetInstance().DetailGridRows); + SetupStore("ListGridColumns", Config::GetInstance().ListGridColumns); + SetupStore("ListGridRows", Config::GetInstance().ListGridRows); + SetupStore("ExtrasGridColumns", Config::GetInstance().ExtrasGridColumns); + SetupStore("ExtrasGridRows", Config::GetInstance().ExtrasGridRows); + SetupStore("DefaultViewMode", Config::GetInstance().DefaultViewMode); + SetupStore("UseMpv", Config::GetInstance().UseMpv); + SetupStore("ScrollByPage", Config::GetInstance().ScrollByPage); + SetupStore("ScrollAllAround", Config::GetInstance().ScrollAllAround); + SetupStore("UseAc3", Config::GetInstance().ScrollAllAround); + SetupStore("BufferSize", Config::GetInstance().BufferSize); } @@ -17,83 +17,95 @@ #define STRING_SIZE 256 struct ViewEntry { - std::string Name; - std::string PlexPath; + std::string Name; + std::string PlexPath; }; enum ViewMode { - Cover = 0, - List = 1, - Detail = 2 + Cover = 0, + List = 1, + Detail = 2 }; -class Config -{ - +class Config { + public: - static Config& GetInstance() { - static Config instance; - return instance; - } - static const char* viewModeNames[]; - - std::string s_username; - std::string s_password; - std::string s_serverHost; - int ServerPort; - - bool HideMainMenuEntry; - bool UseCustomTranscodeProfile; - bool UsePlexAccount; - bool UseConfiguredServer; - bool UseAc3; - int BufferSize; - - int CoverGridColumns; - int CoverGridRows; - - int ListGridColumns; - int ListGridRows; - - int DetailGridColumns; - int DetailGridRows; - - int ExtrasGridColumns; - int ExtrasGridRows; - - ViewMode DefaultViewMode; - - std::vector<ViewEntry> m_viewentries; - std::vector<ViewEntry> m_serverViewentries; - - bool ScrollByPage; - bool ScrollAllAround; - bool UseMpv; - - std::string GetUUID(); - void SetUUID(const char* uuid); - std::string GetHostname(); - std::string GetLanguage(); - std::string GetUsername(); - std::string GetPassword(); - //int ThumbHeight() { return 1080 / CoverGridRows; }; - //int ThumbWidth() { return 1920 / CoverGridColumns; }; - //int ArtHeight() { return 1080 / 4; }; - //int ArtWidth() { return 1920 / 4; }; - int ThumbHeight() { return 1080; }; - int ThumbWidth() { return 1920; }; - int ArtHeight() { return 1080; }; - int ArtWidth() { return 1920; }; - int BannerHeight() { return 1080 / 2; }; - int BannerWidth() { return 1920 / 2; }; - - bool Parse(const char *name, const char *value); - + static Config &GetInstance() { + static Config instance; + return instance; + } + + static const char *viewModeNames[]; + + std::string s_username; + std::string s_password; + std::string s_serverHost; + int ServerPort; + + bool HideMainMenuEntry; + bool UseCustomTranscodeProfile; + bool UsePlexAccount; + bool UseConfiguredServer; + bool UseAc3; + int BufferSize; + + int CoverGridColumns; + int CoverGridRows; + + int ListGridColumns; + int ListGridRows; + + int DetailGridColumns; + int DetailGridRows; + + int ExtrasGridColumns; + int ExtrasGridRows; + + ViewMode DefaultViewMode; + + std::vector<ViewEntry> m_viewentries; + std::vector<ViewEntry> m_serverViewentries; + + bool ScrollByPage; + bool ScrollAllAround; + bool UseMpv; + + std::string GetUUID(); + + void SetUUID(const char *uuid); + + std::string GetHostname(); + + std::string GetLanguage(); + + std::string GetUsername(); + + std::string GetPassword(); + + //int ThumbHeight() { return 1080 / CoverGridRows; }; + //int ThumbWidth() { return 1920 / CoverGridColumns; }; + //int ArtHeight() { return 1080 / 4; }; + //int ArtWidth() { return 1920 / 4; }; + int ThumbHeight() { return 1080; }; + + int ThumbWidth() { return 1920; }; + + int ArtHeight() { return 1080; }; + + int ArtWidth() { return 1920; }; + + int BannerHeight() { return 1080 / 2; }; + + int BannerWidth() { return 1920 / 2; }; + + bool Parse(const char *name, const char *value); + private: - Config(); - std::string s_uuid; - std::string s_hostname; + Config(); + + std::string s_uuid; + std::string s_hostname; }; @@ -104,38 +116,38 @@ private: /** ** Play plugin menu setup page class. */ -class cMyMenuSetupPage:public cMenuSetupPage -{ - protected: - char Username[STRING_SIZE]; - char Password[STRING_SIZE]; - char Uuid[STRING_SIZE]; - char ServerHost[STRING_SIZE]; - int ServerPort; - int UseConfiguredServer; - int HideMainMenuEntry; - int UseCustomTranscodeProfile; - int UsePlexAccount; - int CoverGridColumns; - int CoverGridRows; - int DetailGridColumns; - int DetailGridRows; - int ListGridColumns; - int ListGridRows; - int ExtrasGridColumns; - int ExtrasGridRows; - int DefaultViewMode; - int UseMpv; - int ScrollByPage; - int ScrollAllAround; - int UseAc3; - int BufferSize; +class cMyMenuSetupPage : public cMenuSetupPage { +protected: + char Username[STRING_SIZE]; + char Password[STRING_SIZE]; + char Uuid[STRING_SIZE]; + char ServerHost[STRING_SIZE]; + int ServerPort; + int UseConfiguredServer; + int HideMainMenuEntry; + int UseCustomTranscodeProfile; + int UsePlexAccount; + int CoverGridColumns; + int CoverGridRows; + int DetailGridColumns; + int DetailGridRows; + int ListGridColumns; + int ListGridRows; + int ExtrasGridColumns; + int ExtrasGridRows; + int DefaultViewMode; + int UseMpv; + int ScrollByPage; + int ScrollAllAround; + int UseAc3; + int BufferSize; virtual void Store(void); - public: - cMyMenuSetupPage(void); - virtual eOSState ProcessKey(eKeys); // handle input +public: + cMyMenuSetupPage(void); + + virtual eOSState ProcessKey(eKeys); // handle input }; #endif // CONFIG_H diff --git a/ControlServer.cpp b/ControlServer.cpp index 31363ae..5344e44 100644 --- a/ControlServer.cpp +++ b/ControlServer.cpp @@ -1,31 +1,27 @@ #include "ControlServer.h" -namespace plexclient -{ +namespace plexclient { -ControlServer::ControlServer() -{ - m_pSvs = new Poco::Net::ServerSocket(3200);; - m_pSrv = new Poco::Net::HTTPServer(new PlexReqHandlerFactory, *m_pSvs, new Poco::Net::HTTPServerParams); -} + ControlServer::ControlServer() { + m_pSvs = new Poco::Net::ServerSocket(3200);; + m_pSrv = new Poco::Net::HTTPServer(new PlexReqHandlerFactory, *m_pSvs, new Poco::Net::HTTPServerParams); + } -void ControlServer::Stop() -{ - Cancel(1); - // Stop the HTTPServer - m_pSrv->stop(); -} + void ControlServer::Stop() { + Cancel(1); + // Stop the HTTPServer + m_pSrv->stop(); + } -void ControlServer::Action() -{ - isyslog("[plex] Starting Controlserver..."); - // start the HTTPServer - m_pSrv->start(); - while(Running()) { - SubscriptionManager::GetInstance().Notify(); - cCondWait::SleepMs(1000); - } -} + void ControlServer::Action() { + isyslog("[plex] Starting Controlserver..."); + // start the HTTPServer + m_pSrv->start(); + while (Running()) { + SubscriptionManager::GetInstance().Notify(); + cCondWait::SleepMs(1000); + } + } } diff --git a/ControlServer.h b/ControlServer.h index 8546fa7..e742fb3 100644 --- a/ControlServer.h +++ b/ControlServer.h @@ -12,29 +12,28 @@ #include <vdr/thread.h> -namespace plexclient -{ +namespace plexclient { -class ControlServer : public cThread -{ + class ControlServer : public cThread { -public: - static ControlServer& GetInstance() { - static ControlServer instance; - return instance; - } - void Stop(); + public: + static ControlServer &GetInstance() { + static ControlServer instance; + return instance; + } -protected: - void Action(); + void Stop(); -private: - ControlServer(); + protected: + void Action(); - Poco::Net::ServerSocket *m_pSvs; - Poco::Net::HTTPServer *m_pSrv; + private: + ControlServer(); -}; + Poco::Net::ServerSocket *m_pSvs; + Poco::Net::HTTPServer *m_pSrv; + + }; } diff --git a/Directory.cpp b/Directory.cpp index d4cbb09..91511b3 100644 --- a/Directory.cpp +++ b/Directory.cpp @@ -3,187 +3,190 @@ #include <Poco/Format.h> #include "tokendefinitions.h" -namespace plexclient -{ - -Directory::Directory(Poco::XML::Node* pNode, PlexServer* Server, MediaContainer* parent) -{ - m_pParent = parent; - m_pServer = Server; - - NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pChildNode = it.nextNode(); - - while(pChildNode) { - if(Poco::icompare(pChildNode->nodeName(), "Directory") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - - m_bAllowSync = GetNodeValueAsBool(pAttribs->getNamedItem("allowSync")); - m_iIndex = GetNodeValueAsInt(pAttribs->getNamedItem("index")); - m_iLeafCount = GetNodeValueAsInt(pAttribs->getNamedItem("leafCount")); - m_iViewedLeafCount = GetNodeValueAsInt(pAttribs->getNamedItem("viewedLeafCount")); - m_iChildCount = GetNodeValueAsInt(pAttribs->getNamedItem("childCount")); - m_fRating = GetNodeValueAsDouble(pAttribs->getNamedItem("rating")); - m_iYear = GetNodeValueAsInt(pAttribs->getNamedItem("year")); - m_sArt = GetNodeValue(pAttribs->getNamedItem("art")); - m_sThumb = GetNodeValue(pAttribs->getNamedItem("thumb")); - m_sKey = GetNodeValue(pAttribs->getNamedItem("key")); - m_sTitle = GetNodeValue(pAttribs->getNamedItem("title")); - m_sTitle1 = GetNodeValue(pAttribs->getNamedItem("title1")); - m_sTitle2 = GetNodeValue(pAttribs->getNamedItem("title2")); - m_sParentTitle = GetNodeValue(pAttribs->getNamedItem("parentTitle")); - m_sComposite = GetNodeValue(pAttribs->getNamedItem("composite")); - m_sLanguage = GetNodeValue(pAttribs->getNamedItem("language")); - m_sUuid = GetNodeValue(pAttribs->getNamedItem("uuid")); - m_tUpdatedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("updatedAt")); - m_tCreatedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("createdAt")); - m_eType = GetNodeValueAsMediaType(pAttribs->getNamedItem("type")); - m_sSummary = GetNodeValue(pAttribs->getNamedItem("summary")); - m_sParentSummary = GetNodeValue(pAttribs->getNamedItem("parentSummary")); - m_sStudio = GetNodeValue(pAttribs->getNamedItem("studio")); - - pAttribs->release(); - } else if(Poco::icompare(pChildNode->nodeName(), "Genre") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_vGenre.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); - pAttribs->release(); - - } else if(Poco::icompare(pChildNode->nodeName(), "Role") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_vRole.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); - pAttribs->release(); - } - pChildNode = it.nextNode(); - } - if(m_sTitle2.empty()) m_sTitle2 = parent->m_sTitle2; -} - -std::string Directory::GetTitle() -{ - std::string seriesTitle = m_sParentTitle; - if(seriesTitle.empty() && m_pParent) - seriesTitle = m_pParent->m_sParentTitle; - - switch(m_eType) { - case MediaType::SEASON: - return Poco::format(tr("%s - Season %d"), seriesTitle, m_iIndex); - default: - return m_sTitle; - } -} +namespace plexclient { + + Directory::Directory(Poco::XML::Node *pNode, PlexServer *Server, MediaContainer *parent) { + m_pParent = parent; + m_pServer = Server; + + NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pChildNode = it.nextNode(); + + while (pChildNode) { + if (Poco::icompare(pChildNode->nodeName(), "Directory") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + + m_bAllowSync = GetNodeValueAsBool(pAttribs->getNamedItem("allowSync")); + m_iIndex = GetNodeValueAsInt(pAttribs->getNamedItem("index")); + m_iLeafCount = GetNodeValueAsInt(pAttribs->getNamedItem("leafCount")); + m_iViewedLeafCount = GetNodeValueAsInt(pAttribs->getNamedItem("viewedLeafCount")); + m_iChildCount = GetNodeValueAsInt(pAttribs->getNamedItem("childCount")); + m_fRating = GetNodeValueAsDouble(pAttribs->getNamedItem("rating")); + m_iYear = GetNodeValueAsInt(pAttribs->getNamedItem("year")); + m_sArt = GetNodeValue(pAttribs->getNamedItem("art")); + m_sThumb = GetNodeValue(pAttribs->getNamedItem("thumb")); + m_sKey = GetNodeValue(pAttribs->getNamedItem("key")); + m_sTitle = GetNodeValue(pAttribs->getNamedItem("title")); + m_sTitle1 = GetNodeValue(pAttribs->getNamedItem("title1")); + m_sTitle2 = GetNodeValue(pAttribs->getNamedItem("title2")); + m_sParentTitle = GetNodeValue(pAttribs->getNamedItem("parentTitle")); + m_sComposite = GetNodeValue(pAttribs->getNamedItem("composite")); + m_sLanguage = GetNodeValue(pAttribs->getNamedItem("language")); + m_sUuid = GetNodeValue(pAttribs->getNamedItem("uuid")); + m_tUpdatedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("updatedAt")); + m_tCreatedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("createdAt")); + m_eType = GetNodeValueAsMediaType(pAttribs->getNamedItem("type")); + m_sSummary = GetNodeValue(pAttribs->getNamedItem("summary")); + m_sParentSummary = GetNodeValue(pAttribs->getNamedItem("parentSummary")); + m_sStudio = GetNodeValue(pAttribs->getNamedItem("studio")); + + pAttribs->release(); + } else if (Poco::icompare(pChildNode->nodeName(), "Genre") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_vGenre.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); + pAttribs->release(); + + } else if (Poco::icompare(pChildNode->nodeName(), "Role") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_vRole.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); + pAttribs->release(); + } + pChildNode = it.nextNode(); + } + if (m_sTitle2.empty()) m_sTitle2 = parent->m_sTitle2; + } + + std::string Directory::GetTitle() { + std::string seriesTitle = m_sParentTitle; + if (seriesTitle.empty() && m_pParent) + seriesTitle = m_pParent->m_sParentTitle; + + switch (m_eType) { + case MediaType::SEASON: + return Poco::format(tr("%s - Season %d"), seriesTitle, m_iIndex); + default: + return m_sTitle; + } + } #ifdef SKINDESIGNER -void Directory::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, std::function<void(cGridElement*)> OnCached) -{ - if(clear) grid->ClearTokens(); - grid->AddIntToken((int)(eTokenGridInt::viewmode), Config::GetInstance().DefaultViewMode); - grid->AddStringToken((int)(eTokenGridStr::title), m_sTitle.c_str()); - grid->AddIntToken((int)(eTokenGridInt::viewgroup), (int)m_pParent->m_eViewGroup); - - // Thumb, Cover, Episodepicture - bool cached = false; - if(!ThumbUri().empty()) { - std::string thumb = cPictureCache::GetInstance().GetPath(ThumbUri(), Config::GetInstance().ThumbWidth(), Config::GetInstance().ThumbHeight(), cached, OnCached, this); - if (cached) grid->AddStringToken((int)(eTokenGridStr::thumb), thumb.c_str()); - } - grid->AddIntToken((int)(eTokenGridInt::hasthumb), cached); - - // Fanart - cached = false; - if(!ArtUri().empty()) { - std::string art = cPictureCache::GetInstance().GetPath(ArtUri(), Config::GetInstance().ArtWidth(), Config::GetInstance().ArtHeight(), cached); - if (cached) grid->AddStringToken((int)(eTokenGridStr::art), art.c_str()); - } - grid->AddIntToken((int)(eTokenGridInt::hasart), cached); - - if(m_eType == MediaType::UNDEF || m_eType == MediaType::MOVIE || m_eType == MediaType::PHOTO) { - grid->AddIntToken((int)(eTokenGridInt::isdirectory), true); - } - - vector<int> loopInfo; - loopInfo.push_back(m_vRole.size()); - loopInfo.push_back(m_vGenre.size()); - grid->SetLoop(loopInfo); - - int actloopIndex = grid->GetLoopIndex("roles"); - int i = 0; - for(auto it = m_vRole.begin(); it != m_vRole.end(); it++) { - grid->AddLoopToken(actloopIndex, i, (int)(eTokenGridActorLst::roles), it->c_str()); - i++; - } - - int genloopIndex = grid->GetLoopIndex("genres"); - i = 0; - for(auto it = m_vGenre.begin(); it != m_vGenre.end(); it++) { - grid->AddLoopToken(genloopIndex, i, (int)(eTokenGridGenresLst::genres), it->c_str()); - i++; - } - - if(m_eType == MediaType::SHOW) { - grid->AddIntToken((int)(eTokenGridInt::isshow), true); - grid->AddStringToken((int)(eTokenGridStr::summary), m_sSummary.c_str()); - grid->AddIntToken((int)(eTokenGridInt::leafCount), m_iLeafCount); - grid->AddIntToken((int)(eTokenGridInt::viewedLeafCount), m_iViewedLeafCount); - grid->AddIntToken((int)(eTokenGridInt::childCount), m_iChildCount); - grid->AddIntToken((int)(eTokenGridInt::rating), m_fRating*10); - grid->AddStringToken((int)(eTokenGridStr::ratingstring), Poco::format("%.1f", m_fRating).c_str()); - grid->AddStringToken((int)(eTokenGridStr::studio), m_sStudio.c_str()); - - grid->AddIntToken((int)(eTokenGridInt::year), m_iYear); - } - - if(m_eType == MediaType::SEASON) { - grid->AddIntToken((int)(eTokenGridInt::isseason), true); - - std::string summary = m_sParentSummary; - if(m_sParentSummary.empty() && m_pParent) - summary = m_pParent->m_sSummary; - - grid->AddStringToken((int)(eTokenGridStr::summary), summary.c_str()); - grid->AddIntToken((int)(eTokenGridInt::season), m_iIndex); - grid->AddIntToken((int)(eTokenGridInt::leafCount), m_iLeafCount); - grid->AddIntToken((int)(eTokenGridInt::viewedLeafCount), m_iViewedLeafCount); - - std::string seriesTitle = m_sParentTitle; - if(seriesTitle.empty() && m_pParent) - seriesTitle = m_pParent->m_sParentTitle; - - grid->AddStringToken((int)(eTokenGridStr::seriestitle), seriesTitle.c_str()); - grid->AddIntToken((int)(eTokenGridInt::year), m_pParent->m_iParentYear); - } - - // Banner, Seriesbanner - if(m_pParent && !m_pParent->m_sBanner.empty()) { - cached = false; - std::string banner = cPictureCache::GetInstance().GetPath(m_pServer->GetUri() + m_pParent->m_sBanner, Config::GetInstance().BannerWidth(), Config::GetInstance().BannerHeight(), cached, OnCached, this); - if(cached) { - grid->AddIntToken((int)(eTokenGridInt::hasbanner), cached); - grid->AddStringToken((int)(eTokenGridStr::banner), banner.c_str()); - } - } -} -#endif -std::string Directory::ArtUri() -{ - if(!m_sArt.empty()) { - if(m_sArt.find("http://") != std::string::npos) return m_sArt; - if(m_sArt[0] == '/') return m_pServer->GetUri() + m_sArt; - return m_pServer->GetUri() + '/' + m_sArt; - } - if(m_pParent) return m_pParent->ArtUri(); - return ""; -} + void Directory::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, + std::function<void(cGridElement *)> OnCached) { + if (clear) grid->ClearTokens(); + grid->AddIntToken((int) (eTokenGridInt::viewmode), Config::GetInstance().DefaultViewMode); + grid->AddStringToken((int) (eTokenGridStr::title), m_sTitle.c_str()); + grid->AddIntToken((int) (eTokenGridInt::viewgroup), (int) m_pParent->m_eViewGroup); + + // Thumb, Cover, Episodepicture + bool cached = false; + if (!ThumbUri().empty()) { + std::string thumb = cPictureCache::GetInstance().GetPath(ThumbUri(), Config::GetInstance().ThumbWidth(), + Config::GetInstance().ThumbHeight(), cached, + OnCached, this); + if (cached) grid->AddStringToken((int) (eTokenGridStr::thumb), thumb.c_str()); + } + grid->AddIntToken((int) (eTokenGridInt::hasthumb), cached); + + // Fanart + cached = false; + if (!ArtUri().empty()) { + std::string art = cPictureCache::GetInstance().GetPath(ArtUri(), Config::GetInstance().ArtWidth(), + Config::GetInstance().ArtHeight(), cached); + if (cached) grid->AddStringToken((int) (eTokenGridStr::art), art.c_str()); + } + grid->AddIntToken((int) (eTokenGridInt::hasart), cached); + + if (m_eType == MediaType::UNDEF || m_eType == MediaType::MOVIE || m_eType == MediaType::PHOTO) { + grid->AddIntToken((int) (eTokenGridInt::isdirectory), true); + } + + vector<int> loopInfo; + loopInfo.push_back(m_vRole.size()); + loopInfo.push_back(m_vGenre.size()); + grid->SetLoop(loopInfo); + + int actloopIndex = grid->GetLoopIndex("roles"); + int i = 0; + for (auto it = m_vRole.begin(); it != m_vRole.end(); it++) { + grid->AddLoopToken(actloopIndex, i, (int) (eTokenGridActorLst::roles), it->c_str()); + i++; + } + + int genloopIndex = grid->GetLoopIndex("genres"); + i = 0; + for (auto it = m_vGenre.begin(); it != m_vGenre.end(); it++) { + grid->AddLoopToken(genloopIndex, i, (int) (eTokenGridGenresLst::genres), it->c_str()); + i++; + } + + if (m_eType == MediaType::SHOW) { + grid->AddIntToken((int) (eTokenGridInt::isshow), true); + grid->AddStringToken((int) (eTokenGridStr::summary), m_sSummary.c_str()); + grid->AddIntToken((int) (eTokenGridInt::leafCount), m_iLeafCount); + grid->AddIntToken((int) (eTokenGridInt::viewedLeafCount), m_iViewedLeafCount); + grid->AddIntToken((int) (eTokenGridInt::childCount), m_iChildCount); + grid->AddIntToken((int) (eTokenGridInt::rating), m_fRating * 10); + grid->AddStringToken((int) (eTokenGridStr::ratingstring), Poco::format("%.1f", m_fRating).c_str()); + grid->AddStringToken((int) (eTokenGridStr::studio), m_sStudio.c_str()); + + grid->AddIntToken((int) (eTokenGridInt::year), m_iYear); + } + + if (m_eType == MediaType::SEASON) { + grid->AddIntToken((int) (eTokenGridInt::isseason), true); + + std::string summary = m_sParentSummary; + if (m_sParentSummary.empty() && m_pParent) + summary = m_pParent->m_sSummary; + + grid->AddStringToken((int) (eTokenGridStr::summary), summary.c_str()); + grid->AddIntToken((int) (eTokenGridInt::season), m_iIndex); + grid->AddIntToken((int) (eTokenGridInt::leafCount), m_iLeafCount); + grid->AddIntToken((int) (eTokenGridInt::viewedLeafCount), m_iViewedLeafCount); + + std::string seriesTitle = m_sParentTitle; + if (seriesTitle.empty() && m_pParent) + seriesTitle = m_pParent->m_sParentTitle; + + grid->AddStringToken((int) (eTokenGridStr::seriestitle), seriesTitle.c_str()); + grid->AddIntToken((int) (eTokenGridInt::year), m_pParent->m_iParentYear); + } + + // Banner, Seriesbanner + if (m_pParent && !m_pParent->m_sBanner.empty()) { + cached = false; + std::string banner = cPictureCache::GetInstance().GetPath(m_pServer->GetUri() + m_pParent->m_sBanner, + Config::GetInstance().BannerWidth(), + Config::GetInstance().BannerHeight(), cached, + OnCached, this); + if (cached) { + grid->AddIntToken((int) (eTokenGridInt::hasbanner), cached); + grid->AddStringToken((int) (eTokenGridStr::banner), banner.c_str()); + } + } + } -std::string Directory::ThumbUri() -{ - if(!m_sThumb.empty()) { - if(m_sThumb.find("http://") != std::string::npos) return m_sThumb; - if(m_sThumb[0] == '/') return m_pServer->GetUri() + m_sThumb; - return m_pServer->GetUri() + '/' + m_sThumb; - } - if(m_pParent) return m_pParent->ThumbUri(); - return ""; -} +#endif + + std::string Directory::ArtUri() { + if (!m_sArt.empty()) { + if (m_sArt.find("http://") != std::string::npos) return m_sArt; + if (m_sArt[0] == '/') return m_pServer->GetUri() + m_sArt; + return m_pServer->GetUri() + '/' + m_sArt; + } + if (m_pParent) return m_pParent->ArtUri(); + return ""; + } + + std::string Directory::ThumbUri() { + if (!m_sThumb.empty()) { + if (m_sThumb.find("http://") != std::string::npos) return m_sThumb; + if (m_sThumb[0] == '/') return m_pServer->GetUri() + m_sThumb; + return m_pServer->GetUri() + '/' + m_sThumb; + } + if (m_pParent) return m_pParent->ThumbUri(); + return ""; + } } diff --git a/Directory.h b/Directory.h index 97d7c85..f3a959f 100644 --- a/Directory.h +++ b/Directory.h @@ -12,10 +12,13 @@ #include <Poco/String.h> #include <memory> + #ifdef SKINDESIGNER - #include <libskindesignerapi/osdelements.h> - #include "pictureCache.h" - #include "viewGridNavigator.h" + +#include <libskindesignerapi/osdelements.h> +#include "pictureCache.h" +#include "viewGridNavigator.h" + #endif #include "XmlObject.h" @@ -30,58 +33,62 @@ using Poco::XML::Node; using Poco::XML::AutoPtr; using Poco::Exception; -namespace plexclient -{ -class MediaContainer; +namespace plexclient { + class MediaContainer; -class Directory: private XmlObject + class Directory : private XmlObject #ifdef SKINDESIGNER -, public cGridElement + , public cGridElement #endif -{ -public: - Directory(Poco::XML::Node* pNode, PlexServer* Server, MediaContainer* parent); - -public: - bool m_bAllowSync; - int m_iIndex; // Season, Episode number - int m_iYear; - int m_iLeafCount; // Total number of Episodes - int m_iViewedLeafCount; // Watched Episodes - int m_iChildCount; // Number of Seasons - double m_fRating; - std::string m_sSummary; - std::string m_sParentSummary; - std::string m_sTitle; - std::string m_sTitle1; - std::string m_sTitle2; - std::string m_sParentTitle; - std::string m_sComposite; - std::string m_sLanguage; - std::string m_sUuid; - std::string m_sArt; - std::string m_sThumb; - std::string m_sStudio; - Poco::Timestamp m_tUpdatedAt; - Poco::Timestamp m_tCreatedAt; - std::string m_sKey; - - std::vector<std::string> m_vGenre; - std::vector<std::string> m_vRole; - - MediaType m_eType; - PlexServer* m_pServer; - MediaContainer* m_pParent; - - virtual std::string GetTitle(); - std::string ArtUri(); - std::string ThumbUri(); - + { + public: + Directory(Poco::XML::Node *pNode, PlexServer *Server, MediaContainer *parent); + + public: + bool m_bAllowSync; + int m_iIndex; // Season, Episode number + int m_iYear; + int m_iLeafCount; // Total number of Episodes + int m_iViewedLeafCount; // Watched Episodes + int m_iChildCount; // Number of Seasons + double m_fRating; + std::string m_sSummary; + std::string m_sParentSummary; + std::string m_sTitle; + std::string m_sTitle1; + std::string m_sTitle2; + std::string m_sParentTitle; + std::string m_sComposite; + std::string m_sLanguage; + std::string m_sUuid; + std::string m_sArt; + std::string m_sThumb; + std::string m_sStudio; + Poco::Timestamp m_tUpdatedAt; + Poco::Timestamp m_tCreatedAt; + std::string m_sKey; + + std::vector<std::string> m_vGenre; + std::vector<std::string> m_vRole; + + MediaType m_eType; + PlexServer *m_pServer; + MediaContainer *m_pParent; + + virtual std::string GetTitle(); + + std::string ArtUri(); + + std::string ThumbUri(); + #ifdef SKINDESIGNER - // gridElement - virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, std::function<void(cGridElement*)> OnCached = NULL); + + // gridElement + virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, + std::function<void(cGridElement *)> OnCached = NULL); + #endif -}; + }; } @@ -1,67 +1,66 @@ #include "Media.h" #include "tokendefinitions.h" -namespace plexclient -{ +namespace plexclient { -Media::Media(Poco::XML::Node* pNode) -{ - NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pChildNode = it.nextNode(); + Media::Media(Poco::XML::Node *pNode) { + NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pChildNode = it.nextNode(); - while(pChildNode) { - if(Poco::icompare(pChildNode->nodeName(), "Media") == 0) { + while (pChildNode) { + if (Poco::icompare(pChildNode->nodeName(), "Media") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_sVideoResolution = GetNodeValue(pAttribs->getNamedItem("videoResolution")); - m_iId = GetNodeValueAsInt(pAttribs->getNamedItem("id")); - m_lDuration = GetNodeValueAsLong(pAttribs->getNamedItem("duration")); - m_iBitrate = GetNodeValueAsInt(pAttribs->getNamedItem("bitrate")); - m_iWidth = GetNodeValueAsInt(pAttribs->getNamedItem("width")); - m_iHeight = GetNodeValueAsInt(pAttribs->getNamedItem("height")); - m_sAspectRatio = GetNodeValue(pAttribs->getNamedItem("aspectRatio")); - m_iAudioChannels = GetNodeValueAsInt(pAttribs->getNamedItem("audioChannels")); - m_sAudioCodec = GetNodeValue(pAttribs->getNamedItem("audioCodec")); - m_sVideoCodec = GetNodeValue(pAttribs->getNamedItem("videoCodec")); - m_sContainer = GetNodeValue(pAttribs->getNamedItem("container")); - m_VideoFrameRate = GetNodeValue(pAttribs->getNamedItem("videoFrameRate")); + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_sVideoResolution = GetNodeValue(pAttribs->getNamedItem("videoResolution")); + m_iId = GetNodeValueAsInt(pAttribs->getNamedItem("id")); + m_lDuration = GetNodeValueAsLong(pAttribs->getNamedItem("duration")); + m_iBitrate = GetNodeValueAsInt(pAttribs->getNamedItem("bitrate")); + m_iWidth = GetNodeValueAsInt(pAttribs->getNamedItem("width")); + m_iHeight = GetNodeValueAsInt(pAttribs->getNamedItem("height")); + m_sAspectRatio = GetNodeValue(pAttribs->getNamedItem("aspectRatio")); + m_iAudioChannels = GetNodeValueAsInt(pAttribs->getNamedItem("audioChannels")); + m_sAudioCodec = GetNodeValue(pAttribs->getNamedItem("audioCodec")); + m_sVideoCodec = GetNodeValue(pAttribs->getNamedItem("videoCodec")); + m_sContainer = GetNodeValue(pAttribs->getNamedItem("container")); + m_VideoFrameRate = GetNodeValue(pAttribs->getNamedItem("videoFrameRate")); - pAttribs->release(); + pAttribs->release(); - } - if(Poco::icompare(pChildNode->nodeName(), "Part") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_sPartKey = GetNodeValue(pAttribs->getNamedItem("key")); - m_iPartId = GetNodeValueAsInt(pAttribs->getNamedItem("id")); - m_lPartDuration = GetNodeValueAsLong(pAttribs->getNamedItem("duration")); - m_sPartFile = GetNodeValue(pAttribs->getNamedItem("file")); - m_lPartSize = GetNodeValueAsLong(pAttribs->getNamedItem("size")); - m_sPartContainer = GetNodeValue(pAttribs->getNamedItem("container")); + } + if (Poco::icompare(pChildNode->nodeName(), "Part") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_sPartKey = GetNodeValue(pAttribs->getNamedItem("key")); + m_iPartId = GetNodeValueAsInt(pAttribs->getNamedItem("id")); + m_lPartDuration = GetNodeValueAsLong(pAttribs->getNamedItem("duration")); + m_sPartFile = GetNodeValue(pAttribs->getNamedItem("file")); + m_lPartSize = GetNodeValueAsLong(pAttribs->getNamedItem("size")); + m_sPartContainer = GetNodeValue(pAttribs->getNamedItem("container")); - pAttribs->release(); - } - if(Poco::icompare(pChildNode->nodeName(), "Stream") == 0) { - m_vStreams.push_back(Stream(pChildNode)); - } - pChildNode = it.nextNode(); - } -} + pAttribs->release(); + } + if (Poco::icompare(pChildNode->nodeName(), "Stream") == 0) { + m_vStreams.push_back(Stream(pChildNode)); + } + pChildNode = it.nextNode(); + } + } #ifdef SKINDESIGNER -void Media::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid) -{ - grid->AddStringToken((int)(eTokenGridStr::videoResolution), m_sVideoResolution.c_str()); - grid->AddIntToken((int)(eTokenGridInt::bitrate), m_iBitrate); - grid->AddIntToken((int)(eTokenGridInt::width), m_iWidth); - grid->AddIntToken((int)(eTokenGridInt::height), m_iHeight); - grid->AddIntToken((int)(eTokenGridInt::audioChannels), m_iAudioChannels); - grid->AddStringToken((int)(eTokenGridStr::aspectRatio), m_sAspectRatio.c_str()); - grid->AddStringToken((int)(eTokenGridStr::audioCodec), m_sAudioCodec.c_str()); - grid->AddStringToken((int)(eTokenGridStr::videoCodec), m_sVideoCodec.c_str()); - grid->AddStringToken((int)(eTokenGridStr::container), m_sContainer.c_str()); - grid->AddStringToken((int)(eTokenGridStr::videoFrameRate), m_VideoFrameRate.c_str()); -} + + void Media::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid) { + grid->AddStringToken((int) (eTokenGridStr::videoResolution), m_sVideoResolution.c_str()); + grid->AddIntToken((int) (eTokenGridInt::bitrate), m_iBitrate); + grid->AddIntToken((int) (eTokenGridInt::width), m_iWidth); + grid->AddIntToken((int) (eTokenGridInt::height), m_iHeight); + grid->AddIntToken((int) (eTokenGridInt::audioChannels), m_iAudioChannels); + grid->AddStringToken((int) (eTokenGridStr::aspectRatio), m_sAspectRatio.c_str()); + grid->AddStringToken((int) (eTokenGridStr::audioCodec), m_sAudioCodec.c_str()); + grid->AddStringToken((int) (eTokenGridStr::videoCodec), m_sVideoCodec.c_str()); + grid->AddStringToken((int) (eTokenGridStr::container), m_sContainer.c_str()); + grid->AddStringToken((int) (eTokenGridStr::videoFrameRate), m_VideoFrameRate.c_str()); + } + #endif } @@ -14,16 +14,19 @@ #include <vector> #include <iostream> + #ifdef SKINDESIGNER - #include <libskindesignerapi/osdelements.h> + +#include <libskindesignerapi/osdelements.h> + #endif + #include <memory> #include "XmlObject.h" // Base class: model::XmlObject #include "Stream.h" - using Poco::XML::DOMParser; using Poco::XML::Document; using Poco::XML::NodeIterator; @@ -32,42 +35,43 @@ using Poco::XML::Node; using Poco::XML::AutoPtr; using Poco::Exception; -namespace plexclient -{ - -class Media: XmlObject -{ - public: - Media() {}; - Media(Poco::XML::Node* pNode); - -public: - std::string m_sVideoResolution; - int m_iId; - long m_lDuration; - int m_iBitrate; - int m_iWidth; - int m_iHeight; - std::string m_sAspectRatio; - int m_iAudioChannels; - std::string m_sAudioCodec; - std::string m_sVideoCodec; - std::string m_sContainer; - std::string m_VideoFrameRate; - - std::string m_sPartKey; - int m_iPartId; - long m_lPartDuration; - std::string m_sPartFile; - long m_lPartSize; - std::string m_sPartContainer; - - std::vector<Stream> m_vStreams; - -#ifdef SKINDESIGNER - void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid); +namespace plexclient { + + class Media : XmlObject { + public: + Media() { }; + + Media(Poco::XML::Node *pNode); + + public: + std::string m_sVideoResolution; + int m_iId; + long m_lDuration; + int m_iBitrate; + int m_iWidth; + int m_iHeight; + std::string m_sAspectRatio; + int m_iAudioChannels; + std::string m_sAudioCodec; + std::string m_sVideoCodec; + std::string m_sContainer; + std::string m_VideoFrameRate; + + std::string m_sPartKey; + int m_iPartId; + long m_lPartDuration; + std::string m_sPartFile; + long m_lPartSize; + std::string m_sPartContainer; + + std::vector<Stream> m_vStreams; + +#ifdef SKINDESIGNER + + void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid); + #endif -}; + }; } diff --git a/MediaContainer.cpp b/MediaContainer.cpp index 264d33b..0fe2137 100644 --- a/MediaContainer.cpp +++ b/MediaContainer.cpp @@ -1,92 +1,91 @@ #include "MediaContainer.h" #ifdef SKINDESIGNER - #include "pictureCache.h" + +#include "pictureCache.h" + #endif -namespace plexclient -{ -MediaContainer::MediaContainer(std::istream* response) : MediaContainer(response, NULL) {} - -MediaContainer::MediaContainer(std::istream* response, PlexServer* Server) -{ - m_pServer = Server; - m_eViewGroup = MediaType::UNDEF; - try { - InputSource src(*response); - DOMParser parser; - Poco::XML::AutoPtr<Document> pDoc = parser.parse(&src); - - NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pNode = it.nextNode(); - while(pNode) { - if(Poco::icompare(pNode->nodeName(), "MediaContainer") == 0) { - Poco::XML::NamedNodeMap* pAttribs = pNode->attributes(); - - m_sTitle = GetNodeValue(pAttribs->getNamedItem("title")); - m_sTitle1 = GetNodeValue(pAttribs->getNamedItem("title1")); - m_sTitle2 = GetNodeValue(pAttribs->getNamedItem("title2")); - m_sGrandparentTitle = GetNodeValue(pAttribs->getNamedItem("grandparentTitle")); - m_sParentTitle = GetNodeValue(pAttribs->getNamedItem("parentTitle")); - m_iParentIndex = GetNodeValueAsInt(pAttribs->getNamedItem("parentIndex")); - m_sThumb = GetNodeValue(pAttribs->getNamedItem("thumb")); - m_sBanner = GetNodeValue(pAttribs->getNamedItem("banner")); - m_eViewGroup = GetNodeValueAsMediaType(pAttribs->getNamedItem("viewGroup")); - m_sLibrarySectionTitle = GetNodeValue(pAttribs->getNamedItem("librarySectionTitle")); - m_sLibrarySectionUUID = GetNodeValue(pAttribs->getNamedItem("librarySectionUUID")); - m_iLibrarySectionID = GetNodeValueAsInt(pAttribs->getNamedItem("librarySectionID")); - m_sMediaTagPrefix = GetNodeValue(pAttribs->getNamedItem("mediaTagPrefix")); - m_iSize = GetNodeValueAsInt(pAttribs->getNamedItem("size")); - m_bAllowSync = GetNodeValueAsBool(pAttribs->getNamedItem("allowSync")); - m_sArt = GetNodeValue(pAttribs->getNamedItem("art")); - m_sSummary = GetNodeValue(pAttribs->getNamedItem("summary")); - m_iParentIndex = GetNodeValueAsInt(pAttribs->getNamedItem("parentIndex")); - m_iParentYear = GetNodeValueAsInt(pAttribs->getNamedItem("parentYear")); - - pAttribs->release(); - } else if(Poco::icompare(pNode->nodeName(), "Directory") == 0) { - m_vDirectories.push_back(Directory(pNode, m_pServer, this)); - } else if(Poco::icompare(pNode->nodeName(), "Video") == 0) { - m_vVideos.push_back(cVideo(pNode, m_pServer, this)); - } else if(Poco::icompare(pNode->nodeName(), "Device") == 0) { - m_vDevices.push_back(Device(pNode, this)); - } else if(Poco::icompare(pNode->nodeName(), "Playlist") == 0) { - m_vPlaylists.push_back(Playlist(pNode, this)); - } - - pNode = it.nextNode(); - } - - } catch(Exception &exc) { - std::cerr << exc.displayText() << std::endl; - } -} +namespace plexclient { + MediaContainer::MediaContainer(std::istream *response) : MediaContainer(response, NULL) { } -std::string MediaContainer::ArtUri() -{ - if(m_sArt.find("http://") != std::string::npos) return m_sArt; - return m_pServer->GetUri() + m_sArt; -} + MediaContainer::MediaContainer(std::istream *response, PlexServer *Server) { + m_pServer = Server; + m_eViewGroup = MediaType::UNDEF; + try { + InputSource src(*response); + DOMParser parser; + Poco::XML::AutoPtr<Document> pDoc = parser.parse(&src); -std::string MediaContainer::ThumbUri() -{ - if(m_sThumb.find("http://") != std::string::npos) return m_sThumb; - return m_pServer->GetUri() + m_sThumb; -} + NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pNode = it.nextNode(); + while (pNode) { + if (Poco::icompare(pNode->nodeName(), "MediaContainer") == 0) { + Poco::XML::NamedNodeMap *pAttribs = pNode->attributes(); + + m_sTitle = GetNodeValue(pAttribs->getNamedItem("title")); + m_sTitle1 = GetNodeValue(pAttribs->getNamedItem("title1")); + m_sTitle2 = GetNodeValue(pAttribs->getNamedItem("title2")); + m_sGrandparentTitle = GetNodeValue(pAttribs->getNamedItem("grandparentTitle")); + m_sParentTitle = GetNodeValue(pAttribs->getNamedItem("parentTitle")); + m_iParentIndex = GetNodeValueAsInt(pAttribs->getNamedItem("parentIndex")); + m_sThumb = GetNodeValue(pAttribs->getNamedItem("thumb")); + m_sBanner = GetNodeValue(pAttribs->getNamedItem("banner")); + m_eViewGroup = GetNodeValueAsMediaType(pAttribs->getNamedItem("viewGroup")); + m_sLibrarySectionTitle = GetNodeValue(pAttribs->getNamedItem("librarySectionTitle")); + m_sLibrarySectionUUID = GetNodeValue(pAttribs->getNamedItem("librarySectionUUID")); + m_iLibrarySectionID = GetNodeValueAsInt(pAttribs->getNamedItem("librarySectionID")); + m_sMediaTagPrefix = GetNodeValue(pAttribs->getNamedItem("mediaTagPrefix")); + m_iSize = GetNodeValueAsInt(pAttribs->getNamedItem("size")); + m_bAllowSync = GetNodeValueAsBool(pAttribs->getNamedItem("allowSync")); + m_sArt = GetNodeValue(pAttribs->getNamedItem("art")); + m_sSummary = GetNodeValue(pAttribs->getNamedItem("summary")); + m_iParentIndex = GetNodeValueAsInt(pAttribs->getNamedItem("parentIndex")); + m_iParentYear = GetNodeValueAsInt(pAttribs->getNamedItem("parentYear")); + + pAttribs->release(); + } else if (Poco::icompare(pNode->nodeName(), "Directory") == 0) { + m_vDirectories.push_back(Directory(pNode, m_pServer, this)); + } else if (Poco::icompare(pNode->nodeName(), "Video") == 0) { + m_vVideos.push_back(cVideo(pNode, m_pServer, this)); + } else if (Poco::icompare(pNode->nodeName(), "Device") == 0) { + m_vDevices.push_back(Device(pNode, this)); + } else if (Poco::icompare(pNode->nodeName(), "Playlist") == 0) { + m_vPlaylists.push_back(Playlist(pNode, this)); + } + + pNode = it.nextNode(); + } + + } catch (Exception &exc) { + std::cerr << exc.displayText() << std::endl; + } + } + + std::string MediaContainer::ArtUri() { + if (m_sArt.find("http://") != std::string::npos) return m_sArt; + return m_pServer->GetUri() + m_sArt; + } + + std::string MediaContainer::ThumbUri() { + if (m_sThumb.find("http://") != std::string::npos) return m_sThumb; + return m_pServer->GetUri() + m_sThumb; + } #ifdef SKINDESIGNER -void MediaContainer::PreCache() -{ - bool foo; - for(std::vector<plexclient::cVideo>::iterator it = m_vVideos.begin(); it != m_vVideos.end(); ++it) { - if(!it->m_sThumb.empty()) cPictureCache::GetInstance().GetPath(it->ThumbUri(), 1280, 720, foo); - if(!it->m_sArt.empty()) cPictureCache::GetInstance().GetPath(it->ArtUri(), 1920, 1080, foo); - } + + void MediaContainer::PreCache() { + bool foo; + for (std::vector<plexclient::cVideo>::iterator it = m_vVideos.begin(); it != m_vVideos.end(); ++it) { + if (!it->m_sThumb.empty()) cPictureCache::GetInstance().GetPath(it->ThumbUri(), 1280, 720, foo); + if (!it->m_sArt.empty()) cPictureCache::GetInstance().GetPath(it->ArtUri(), 1920, 1080, foo); + } /* for(std::vector<plexclient::Directory>::iterator it = m_vDirectories.begin(); it != m_vDirectories.end(); ++it) { if(!it->m_sThumb.empty()) cPictureCache::GetInstance().GetPath(it->ThumbUri(), 1280, 720, foo); if(!it->m_sArt.empty()) cPictureCache::GetInstance().GetPath(it->ArtUri(), 1920, 1080, foo); }*/ -} + } + #endif } diff --git a/MediaContainer.h b/MediaContainer.h index c6cb14e..61e102d 100644 --- a/MediaContainer.h +++ b/MediaContainer.h @@ -31,56 +31,61 @@ using Poco::XML::Node; using Poco::XML::AutoPtr; using Poco::Exception; -namespace plexclient -{ -class cVideo; -class Directory; -class Device; -class Playlist; - -class MediaContainer: XmlObject -{ -public: - MediaContainer(std::istream *response, PlexServer* Server); - MediaContainer(std::istream *response); - -protected: - - -public: - std::vector<Directory> m_vDirectories; - std::vector<cVideo> m_vVideos; - std::vector<Device> m_vDevices; - std::vector<Playlist> m_vPlaylists; - - bool m_bAllowSync; - std::string m_sArt; - std::string m_sThumb; - std::string m_sBanner; - std::string m_sTitle; - std::string m_sTitle1; - std::string m_sTitle2; - std::string m_sGrandparentTitle; - MediaType m_eViewGroup; - int m_iLibrarySectionID; - std::string m_sLibrarySectionTitle; - std::string m_sLibrarySectionUUID; - std::string m_sMediaTagPrefix; - int m_iSize; - std::string m_sSummary; - int m_iParentIndex; - std::string m_sParentTitle; - int m_iParentYear; - - PlexServer* m_pServer; - - std::string ThumbUri(); - std::string ArtUri(); +namespace plexclient { + class cVideo; + + class Directory; + + class Device; + + class Playlist; + + class MediaContainer : XmlObject { + public: + MediaContainer(std::istream *response, PlexServer *Server); + + MediaContainer(std::istream *response); + + protected: + + + public: + std::vector<Directory> m_vDirectories; + std::vector<cVideo> m_vVideos; + std::vector<Device> m_vDevices; + std::vector<Playlist> m_vPlaylists; + + bool m_bAllowSync; + std::string m_sArt; + std::string m_sThumb; + std::string m_sBanner; + std::string m_sTitle; + std::string m_sTitle1; + std::string m_sTitle2; + std::string m_sGrandparentTitle; + MediaType m_eViewGroup; + int m_iLibrarySectionID; + std::string m_sLibrarySectionTitle; + std::string m_sLibrarySectionUUID; + std::string m_sMediaTagPrefix; + int m_iSize; + std::string m_sSummary; + int m_iParentIndex; + std::string m_sParentTitle; + int m_iParentYear; + + PlexServer *m_pServer; + + std::string ThumbUri(); + + std::string ArtUri(); #ifdef SKINDESIGNER - void PreCache(); + + void PreCache(); + #endif -}; + }; } @@ -8,366 +8,367 @@ #include "PlexHelper.h" #include "tokendefinitions.h" -namespace plexclient -{ - -cVideo::cVideo(Poco::XML::Node* pNode, PlexServer* Server, MediaContainer* parent) -{ - m_iMyPlayOffset = 0; - m_lViewoffset = 0; - m_dRating = 0; - m_pServer = Server; - Parse(pNode); - - m_pParent = parent; - if (m_iParentIndex < 0 && m_pParent) { - m_iParentIndex = parent->m_iParentIndex; - } -} - -bool cVideo::UpdateFromServer() -{ - try { - Poco::URI fileuri(Poco::format("%s/library/metadata/%d?includeExtras=1", m_pServer->GetUri(), m_iRatingKey)); - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); - PlexHelper::AddHttpHeader(request); - - Poco::Net::HTTPClientSession session(fileuri.getHost(), fileuri.getPort()); - - session.sendRequest(request); - Poco::Net::HTTPResponse response; - std::istream &rs = session.receiveResponse(response); - - if(response.getStatus() == 200) { - // clear vectors - m_vCountry.clear(); - m_vDirector.clear(); - m_vGenre.clear(); - m_vRole.clear(); - m_vWriter.clear(); - m_vExtras.clear(); - - InputSource src(rs); - DOMParser parser; - Poco::XML::AutoPtr<Document> pDoc = parser.parse(&src); - - NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pNode = it.nextNode(); - while(pNode) { - if(Poco::icompare(pNode->nodeName(), "Video") == 0) { - Parse(pNode); - break; - } - - pNode = it.nextNode(); - } - return true; - } - } catch (Poco::Exception &exc) { - esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); - } - return false; -} - -void cVideo::Parse(Poco::XML::Node* pNode) -{ - NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pChildNode = it.nextNode(); - - while(pChildNode) { - if(Poco::icompare(pChildNode->nodeName(), "Video") == 0) { - - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pNode->attributes(); - - m_iRatingKey = GetNodeValueAsInt(pAttribs->getNamedItem("ratingKey")); - m_iViewCount = GetNodeValueAsInt(pAttribs->getNamedItem("viewCount")); - m_iIndex = GetNodeValueAsInt(pAttribs->getNamedItem("index")); - m_iParentIndex = GetNodeValueAsInt(pAttribs->getNamedItem("parentIndex")); - m_sKey = GetNodeValue(pAttribs->getNamedItem("key")); - m_sStudio = GetNodeValue(pAttribs->getNamedItem("studio")); - m_tType = GetNodeValueAsMediaType(pAttribs->getNamedItem("type")); - m_sTitle = GetNodeValue(pAttribs->getNamedItem("title")); - m_sOriginalTitle = GetNodeValue(pAttribs->getNamedItem("originalTitle")); - m_sGrandparentTitle = GetNodeValue(pAttribs->getNamedItem("grandparentTitle")); - m_sContentRating = GetNodeValue(pAttribs->getNamedItem("contentRating")); - m_sSummary = GetNodeValue(pAttribs->getNamedItem("summary")); - m_sTagline = GetNodeValue(pAttribs->getNamedItem("tagline")); - m_lViewoffset = GetNodeValueAsLong(pAttribs->getNamedItem("viewOffset")); - m_tLastViewedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("lastViewedAt")); - m_iYear = GetNodeValueAsInt(pAttribs->getNamedItem("year")); - m_sThumb = GetNodeValue(pAttribs->getNamedItem("thumb")); - m_sArt = GetNodeValue(pAttribs->getNamedItem("art")); - m_sGrandparentThumb = GetNodeValue(pAttribs->getNamedItem("grandparentThumb")); - m_sGrandparentArt = GetNodeValue(pAttribs->getNamedItem("grandparentArt")); - m_iDuration = GetNodeValueAsLong(pAttribs->getNamedItem("duration")); - m_dRating = GetNodeValueAsDouble(pAttribs->getNamedItem("rating")); - m_tAddedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("addedAt")); - m_tUpdatedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("updatedAt")); - m_tOriginallyAvailableAt = GetNodeValueAsDateTime(pAttribs->getNamedItem("originallyAvailableAt")); - m_eExtraType = GetNodeValueAsExtraType(pAttribs->getNamedItem("extraType")); - - pAttribs->release(); - - } else if(Poco::icompare(pChildNode->nodeName(), "Media") == 0) { - m_Media = Media(pChildNode); - } else if(Poco::icompare(pChildNode->nodeName(), "Genre") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_vGenre.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); - pAttribs->release(); - - } else if(Poco::icompare(pChildNode->nodeName(), "Writer") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_vWriter.push_back(GetNodeValue(pChildNode)); - pAttribs->release(); - - } else if(Poco::icompare(pChildNode->nodeName(), "Director") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_vDirector.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); - pAttribs->release(); - - } else if(Poco::icompare(pChildNode->nodeName(), "Country") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_vCountry.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); - pAttribs->release(); - - } else if(Poco::icompare(pChildNode->nodeName(), "Role") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_vRole.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); - pAttribs->release(); - - } else if(Poco::icompare(pChildNode->nodeName(), "Collection") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - m_sCollection = GetNodeValue(pAttribs->getNamedItem("tag")); - pAttribs->release(); - } else if(Poco::icompare(pChildNode->nodeName(), "Extras") == 0) { - ParseExtras(pChildNode); - } - pChildNode = it.nextNode(); - } -} - -void cVideo::ParseExtras(Poco::XML::Node* pNode) -{ - NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pChildNode = it.nextNode(); - - while(pChildNode) { - if(Poco::icompare(pChildNode->nodeName(), "Video") == 0) { - m_vExtras.push_back(cVideo(pChildNode, m_pServer, NULL)); - } - pChildNode = it.nextNode(); - } -} - -std::string cVideo::GetTitle() -{ - std::string res = m_sTitle; - - std::string seriesTitle = m_sGrandparentTitle; - if(seriesTitle.empty() && m_pParent) - seriesTitle = m_pParent->m_sGrandparentTitle; - - switch(m_tType) { - case MediaType::MOVIE: - if(m_iYear > 0) { - res = Poco::format("%s (%d)", m_sTitle, m_iYear); - } else { - res = m_sTitle; - } - break; - case MediaType::EPISODE: - res = Poco::format("%s - %02dx%02d - %s", seriesTitle, m_iParentIndex, m_iIndex, m_sTitle); - break; - default: - break; - } - return res; -} - -bool cVideo::SetStream(Stream* stream) -{ - try { - Poco::Net::HTTPClientSession session(m_pServer->GetHost(), m_pServer->GetPort()); - - std::string uri = Poco::format("/library/parts/%d?%s&X-Plex-Token=%s", m_Media.m_iPartId, stream->GetSetStreamQuery(), m_pServer->GetAuthToken()); - Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_PUT, uri); - session.sendRequest(req); - - Poco::Net::HTTPResponse resp; - session.receiveResponse(resp); - - if(resp.getStatus() == 200) { - dsyslog("[plex]: Set Stream: %s", uri.c_str()); - return true; - } - return false; - } catch (Poco::Exception &exc) { - esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); - return false; - } -} - -bool cVideo::SetUnwatched() -{ - try { - std::string uri = Poco::format("/:/unscrobble?key=%d&identifier=com.plexapp.plugins.library", m_iRatingKey); - - bool ok; - auto cSession = m_pServer->MakeRequest(ok, uri); - Poco::Net::HTTPResponse resp; - cSession->receiveResponse(resp); - - if(resp.getStatus() == 200) { - dsyslog("[plex]: Set Unwatched: %s", uri.c_str()); - return true; - } - return false; - } catch (Poco::Exception &exc) { - esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); - return false; - } -} - -bool cVideo::SetWatched() -{ - try { - std::string uri = Poco::format("/:/scrobble?key=%d&identifier=com.plexapp.plugins.library", m_iRatingKey); - - bool ok; - auto cSession = m_pServer->MakeRequest(ok, uri); - - if(ok) { - dsyslog("[plex]: Set Watched: %s", uri.c_str()); - return true; - } - return false; - } catch (Poco::Exception &exc) { - esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); - return false; - } -} +namespace plexclient { + + cVideo::cVideo(Poco::XML::Node *pNode, PlexServer *Server, MediaContainer *parent) { + m_iMyPlayOffset = 0; + m_lViewoffset = 0; + m_dRating = 0; + m_pServer = Server; + Parse(pNode); + + m_pParent = parent; + if (m_iParentIndex < 0 && m_pParent) { + m_iParentIndex = parent->m_iParentIndex; + } + } + + bool cVideo::UpdateFromServer() { + try { + Poco::URI fileuri( + Poco::format("%s/library/metadata/%d?includeExtras=1", m_pServer->GetUri(), m_iRatingKey)); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), + Poco::Net::HTTPMessage::HTTP_1_1); + PlexHelper::AddHttpHeader(request); + + Poco::Net::HTTPClientSession session(fileuri.getHost(), fileuri.getPort()); + + session.sendRequest(request); + Poco::Net::HTTPResponse response; + std::istream &rs = session.receiveResponse(response); + + if (response.getStatus() == 200) { + // clear vectors + m_vCountry.clear(); + m_vDirector.clear(); + m_vGenre.clear(); + m_vRole.clear(); + m_vWriter.clear(); + m_vExtras.clear(); + + InputSource src(rs); + DOMParser parser; + Poco::XML::AutoPtr<Document> pDoc = parser.parse(&src); + + NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pNode = it.nextNode(); + while (pNode) { + if (Poco::icompare(pNode->nodeName(), "Video") == 0) { + Parse(pNode); + break; + } + + pNode = it.nextNode(); + } + return true; + } + } catch (Poco::Exception &exc) { + esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); + } + return false; + } + + void cVideo::Parse(Poco::XML::Node *pNode) { + NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pChildNode = it.nextNode(); + + while (pChildNode) { + if (Poco::icompare(pChildNode->nodeName(), "Video") == 0) { + + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pNode->attributes(); + + m_iRatingKey = GetNodeValueAsInt(pAttribs->getNamedItem("ratingKey")); + m_iViewCount = GetNodeValueAsInt(pAttribs->getNamedItem("viewCount")); + m_iIndex = GetNodeValueAsInt(pAttribs->getNamedItem("index")); + m_iParentIndex = GetNodeValueAsInt(pAttribs->getNamedItem("parentIndex")); + m_sKey = GetNodeValue(pAttribs->getNamedItem("key")); + m_sStudio = GetNodeValue(pAttribs->getNamedItem("studio")); + m_tType = GetNodeValueAsMediaType(pAttribs->getNamedItem("type")); + m_sTitle = GetNodeValue(pAttribs->getNamedItem("title")); + m_sOriginalTitle = GetNodeValue(pAttribs->getNamedItem("originalTitle")); + m_sGrandparentTitle = GetNodeValue(pAttribs->getNamedItem("grandparentTitle")); + m_sContentRating = GetNodeValue(pAttribs->getNamedItem("contentRating")); + m_sSummary = GetNodeValue(pAttribs->getNamedItem("summary")); + m_sTagline = GetNodeValue(pAttribs->getNamedItem("tagline")); + m_lViewoffset = GetNodeValueAsLong(pAttribs->getNamedItem("viewOffset")); + m_tLastViewedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("lastViewedAt")); + m_iYear = GetNodeValueAsInt(pAttribs->getNamedItem("year")); + m_sThumb = GetNodeValue(pAttribs->getNamedItem("thumb")); + m_sArt = GetNodeValue(pAttribs->getNamedItem("art")); + m_sGrandparentThumb = GetNodeValue(pAttribs->getNamedItem("grandparentThumb")); + m_sGrandparentArt = GetNodeValue(pAttribs->getNamedItem("grandparentArt")); + m_iDuration = GetNodeValueAsLong(pAttribs->getNamedItem("duration")); + m_dRating = GetNodeValueAsDouble(pAttribs->getNamedItem("rating")); + m_tAddedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("addedAt")); + m_tUpdatedAt = GetNodeValueAsTimeStamp(pAttribs->getNamedItem("updatedAt")); + m_tOriginallyAvailableAt = GetNodeValueAsDateTime(pAttribs->getNamedItem("originallyAvailableAt")); + m_eExtraType = GetNodeValueAsExtraType(pAttribs->getNamedItem("extraType")); + + pAttribs->release(); + + } else if (Poco::icompare(pChildNode->nodeName(), "Media") == 0) { + m_Media = Media(pChildNode); + } else if (Poco::icompare(pChildNode->nodeName(), "Genre") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_vGenre.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); + pAttribs->release(); + + } else if (Poco::icompare(pChildNode->nodeName(), "Writer") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_vWriter.push_back(GetNodeValue(pChildNode)); + pAttribs->release(); + + } else if (Poco::icompare(pChildNode->nodeName(), "Director") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_vDirector.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); + pAttribs->release(); + + } else if (Poco::icompare(pChildNode->nodeName(), "Country") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_vCountry.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); + pAttribs->release(); + + } else if (Poco::icompare(pChildNode->nodeName(), "Role") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_vRole.push_back(GetNodeValue(pAttribs->getNamedItem("tag"))); + pAttribs->release(); + + } else if (Poco::icompare(pChildNode->nodeName(), "Collection") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + m_sCollection = GetNodeValue(pAttribs->getNamedItem("tag")); + pAttribs->release(); + } else if (Poco::icompare(pChildNode->nodeName(), "Extras") == 0) { + ParseExtras(pChildNode); + } + pChildNode = it.nextNode(); + } + } + + void cVideo::ParseExtras(Poco::XML::Node *pNode) { + NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pChildNode = it.nextNode(); + + while (pChildNode) { + if (Poco::icompare(pChildNode->nodeName(), "Video") == 0) { + m_vExtras.push_back(cVideo(pChildNode, m_pServer, NULL)); + } + pChildNode = it.nextNode(); + } + } + + std::string cVideo::GetTitle() { + std::string res = m_sTitle; + + std::string seriesTitle = m_sGrandparentTitle; + if (seriesTitle.empty() && m_pParent) + seriesTitle = m_pParent->m_sGrandparentTitle; + + switch (m_tType) { + case MediaType::MOVIE: + if (m_iYear > 0) { + res = Poco::format("%s (%d)", m_sTitle, m_iYear); + } else { + res = m_sTitle; + } + break; + case MediaType::EPISODE: + res = Poco::format("%s - %02dx%02d - %s", seriesTitle, m_iParentIndex, m_iIndex, m_sTitle); + break; + default: + break; + } + return res; + } + + bool cVideo::SetStream(Stream *stream) { + try { + Poco::Net::HTTPClientSession session(m_pServer->GetHost(), m_pServer->GetPort()); + + std::string uri = Poco::format("/library/parts/%d?%s&X-Plex-Token=%s", m_Media.m_iPartId, + stream->GetSetStreamQuery(), m_pServer->GetAuthToken()); + Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_PUT, uri); + session.sendRequest(req); + + Poco::Net::HTTPResponse resp; + session.receiveResponse(resp); + + if (resp.getStatus() == 200) { + dsyslog("[plex]: Set Stream: %s", uri.c_str()); + return true; + } + return false; + } catch (Poco::Exception &exc) { + esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); + return false; + } + } + + bool cVideo::SetUnwatched() { + try { + std::string uri = Poco::format("/:/unscrobble?key=%d&identifier=com.plexapp.plugins.library", m_iRatingKey); + + bool ok; + auto cSession = m_pServer->MakeRequest(ok, uri); + Poco::Net::HTTPResponse resp; + cSession->receiveResponse(resp); + + if (resp.getStatus() == 200) { + dsyslog("[plex]: Set Unwatched: %s", uri.c_str()); + return true; + } + return false; + } catch (Poco::Exception &exc) { + esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); + return false; + } + } + + bool cVideo::SetWatched() { + try { + std::string uri = Poco::format("/:/scrobble?key=%d&identifier=com.plexapp.plugins.library", m_iRatingKey); + + bool ok; + auto cSession = m_pServer->MakeRequest(ok, uri); + + if (ok) { + dsyslog("[plex]: Set Watched: %s", uri.c_str()); + return true; + } + return false; + } catch (Poco::Exception &exc) { + esyslog("[plex]: %s: %s", __FUNCTION__, exc.displayText().c_str()); + return false; + } + } #ifdef SKINDESIGNER -void cVideo::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, std::function<void(cGridElement*)> OnCached) -{ - if(clear) grid->ClearTokens(); - grid->AddIntToken((int)(eTokenGridInt::viewmode), Config::GetInstance().DefaultViewMode); - grid->AddStringToken((int)(eTokenGridStr::title), m_sTitle.c_str()); - grid->AddStringToken((int)(eTokenGridStr::orginaltitle), m_sOriginalTitle.c_str()); - grid->AddStringToken((int)(eTokenGridStr::summary), m_sSummary.c_str()); - grid->AddStringToken((int)(eTokenGridStr::tagline), m_sTagline.c_str()); - grid->AddStringToken((int)(eTokenGridStr::contentrating), m_sContentRating.c_str()); - grid->AddIntToken((int)(eTokenGridInt::rating), m_dRating*10); - grid->AddStringToken((int)(eTokenGridStr::ratingstring), Poco::format("%.1f", m_dRating).c_str()); - grid->AddStringToken((int)(eTokenGridStr::studio), m_sStudio.c_str()); - grid->AddIntToken((int)(eTokenGridInt::viewCount), m_iViewCount); - grid->AddIntToken((int)(eTokenGridInt::viewoffset), m_lViewoffset/1000/60); - if(m_iDuration > 0) // avoid division by zero - grid->AddIntToken((int)(eTokenGridInt::viewoffsetpercent), 100.0 / m_iDuration * m_lViewoffset); - else - grid->AddIntToken((int)(eTokenGridInt::viewoffsetpercent), 0); - grid->AddIntToken((int)(eTokenGridInt::duration), m_iDuration/1000/60); - grid->AddIntToken((int)(eTokenGridInt::year), m_iYear); - if(m_pParent) grid->AddIntToken((int)(eTokenGridInt::viewgroup), (int)m_pParent->m_eViewGroup); - - // Thumb, Cover, Episodepicture - bool cached = false; - std::string thumb = cPictureCache::GetInstance().GetPath(ThumbUri(), Config::GetInstance().ThumbWidth(), Config::GetInstance().ThumbHeight(), cached, OnCached, this); - grid->AddIntToken((int)(eTokenGridInt::hasthumb), cached); - if (cached) grid->AddStringToken((int)(eTokenGridStr::thumb), thumb.c_str()); - - // Fanart - cached = false; - std::string art = cPictureCache::GetInstance().GetPath(ArtUri(), Config::GetInstance().ArtWidth(), Config::GetInstance().ArtHeight(), cached); - grid->AddIntToken((int)(eTokenGridInt::hasart), cached); - if (cached) grid->AddStringToken((int)(eTokenGridStr::art), art.c_str()); - - if(m_tType == MediaType::MOVIE) { - grid->AddIntToken((int)(eTokenGridInt::ismovie), true); - } else if (m_tType == MediaType::CLIP) { - grid->AddIntToken((int)(eTokenGridInt::isclip), true); - grid->AddIntToken((int)eTokenGridInt::extratype, (int)m_eExtraType); - } - - vector<int> loopInfo; - loopInfo.push_back(m_vRole.size()); - loopInfo.push_back(m_vGenre.size()); - grid->SetLoop(loopInfo); - - int actloopIndex = grid->GetLoopIndex("roles"); - int i = 0; - for(auto it = m_vRole.begin(); it != m_vRole.end(); it++) { - grid->AddLoopToken(actloopIndex, i, (int)(eTokenGridActorLst::roles), it->c_str()); - i++; - } - - int genloopIndex = grid->GetLoopIndex("genres"); - i = 0; - for(auto it = m_vGenre.begin(); it != m_vGenre.end(); it++) { - grid->AddLoopToken(genloopIndex, i, (int)(eTokenGridGenresLst::genres), it->c_str()); - i++; - } - - grid->AddIntToken((int)(eTokenGridInt::originallyAvailableYear), m_tOriginallyAvailableAt.year()); - grid->AddIntToken((int)(eTokenGridInt::originallyAvailableMonth), m_tOriginallyAvailableAt.month()); - grid->AddIntToken((int)(eTokenGridInt::originallyAvailableDay), m_tOriginallyAvailableAt.day()); - - if(m_tType == MediaType::EPISODE) { - grid->AddIntToken((int)(eTokenGridInt::isepisode), true); - std::string seriesTitle = m_sGrandparentTitle; - if(seriesTitle.empty() && m_pParent) seriesTitle = m_pParent->m_sGrandparentTitle; - grid->AddStringToken((int)(eTokenGridStr::seriestitle), seriesTitle.c_str()); - grid->AddIntToken((int)(eTokenGridInt::season), m_iParentIndex); - grid->AddIntToken((int)(eTokenGridInt::episode), m_iIndex); - - // Seriescover, Seasoncover - cached = false; - std::string grandparentthumbUri = m_sGrandparentThumb; - if(grandparentthumbUri.empty() && m_pParent) { - grandparentthumbUri = m_sThumb; - } - if(!grandparentthumbUri.empty()) { - std::string grandparentThumb = cPictureCache::GetInstance().GetPath(m_pServer->GetUri() + grandparentthumbUri, Config::GetInstance().ThumbWidth(), Config::GetInstance().ThumbHeight(), cached, OnCached, this); - if (cached) grid->AddStringToken((int)(eTokenGridStr::seriesthumb), grandparentThumb.c_str()); - } - grid->AddIntToken((int)(eTokenGridInt::hasseriesthumb), cached); - - // Banner, Seriesbanner - if(m_pParent && !m_pParent->m_sBanner.empty()) { - cached = false; - std::string banner = cPictureCache::GetInstance().GetPath(m_pServer->GetUri() + m_pParent->m_sBanner, Config::GetInstance().BannerWidth(), Config::GetInstance().BannerHeight(), cached, OnCached, this); - if(cached) { - grid->AddIntToken((int)(eTokenGridInt::hasbanner), cached); - grid->AddStringToken((int)(eTokenGridStr::banner), banner.c_str()); - } - } - } - - m_Media.AddTokens(grid); -} + + void cVideo::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, + std::function<void(cGridElement *)> OnCached) { + if (clear) grid->ClearTokens(); + grid->AddIntToken((int) (eTokenGridInt::viewmode), Config::GetInstance().DefaultViewMode); + grid->AddStringToken((int) (eTokenGridStr::title), m_sTitle.c_str()); + grid->AddStringToken((int) (eTokenGridStr::orginaltitle), m_sOriginalTitle.c_str()); + grid->AddStringToken((int) (eTokenGridStr::summary), m_sSummary.c_str()); + grid->AddStringToken((int) (eTokenGridStr::tagline), m_sTagline.c_str()); + grid->AddStringToken((int) (eTokenGridStr::contentrating), m_sContentRating.c_str()); + grid->AddIntToken((int) (eTokenGridInt::rating), m_dRating * 10); + grid->AddStringToken((int) (eTokenGridStr::ratingstring), Poco::format("%.1f", m_dRating).c_str()); + grid->AddStringToken((int) (eTokenGridStr::studio), m_sStudio.c_str()); + grid->AddIntToken((int) (eTokenGridInt::viewCount), m_iViewCount); + grid->AddIntToken((int) (eTokenGridInt::viewoffset), m_lViewoffset / 1000 / 60); + if (m_iDuration > 0) // avoid division by zero + grid->AddIntToken((int) (eTokenGridInt::viewoffsetpercent), 100.0 / m_iDuration * m_lViewoffset); + else + grid->AddIntToken((int) (eTokenGridInt::viewoffsetpercent), 0); + grid->AddIntToken((int) (eTokenGridInt::duration), m_iDuration / 1000 / 60); + grid->AddIntToken((int) (eTokenGridInt::year), m_iYear); + if (m_pParent) grid->AddIntToken((int) (eTokenGridInt::viewgroup), (int) m_pParent->m_eViewGroup); + + // Thumb, Cover, Episodepicture + bool cached = false; + std::string thumb = cPictureCache::GetInstance().GetPath(ThumbUri(), Config::GetInstance().ThumbWidth(), + Config::GetInstance().ThumbHeight(), cached, OnCached, + this); + grid->AddIntToken((int) (eTokenGridInt::hasthumb), cached); + if (cached) grid->AddStringToken((int) (eTokenGridStr::thumb), thumb.c_str()); + + // Fanart + cached = false; + std::string art = cPictureCache::GetInstance().GetPath(ArtUri(), Config::GetInstance().ArtWidth(), + Config::GetInstance().ArtHeight(), cached); + grid->AddIntToken((int) (eTokenGridInt::hasart), cached); + if (cached) grid->AddStringToken((int) (eTokenGridStr::art), art.c_str()); + + if (m_tType == MediaType::MOVIE) { + grid->AddIntToken((int) (eTokenGridInt::ismovie), true); + } else if (m_tType == MediaType::CLIP) { + grid->AddIntToken((int) (eTokenGridInt::isclip), true); + grid->AddIntToken((int) eTokenGridInt::extratype, (int) m_eExtraType); + } + + vector<int> loopInfo; + loopInfo.push_back(m_vRole.size()); + loopInfo.push_back(m_vGenre.size()); + grid->SetLoop(loopInfo); + + int actloopIndex = grid->GetLoopIndex("roles"); + int i = 0; + for (auto it = m_vRole.begin(); it != m_vRole.end(); it++) { + grid->AddLoopToken(actloopIndex, i, (int) (eTokenGridActorLst::roles), it->c_str()); + i++; + } + + int genloopIndex = grid->GetLoopIndex("genres"); + i = 0; + for (auto it = m_vGenre.begin(); it != m_vGenre.end(); it++) { + grid->AddLoopToken(genloopIndex, i, (int) (eTokenGridGenresLst::genres), it->c_str()); + i++; + } + + grid->AddIntToken((int) (eTokenGridInt::originallyAvailableYear), m_tOriginallyAvailableAt.year()); + grid->AddIntToken((int) (eTokenGridInt::originallyAvailableMonth), m_tOriginallyAvailableAt.month()); + grid->AddIntToken((int) (eTokenGridInt::originallyAvailableDay), m_tOriginallyAvailableAt.day()); + + if (m_tType == MediaType::EPISODE) { + grid->AddIntToken((int) (eTokenGridInt::isepisode), true); + std::string seriesTitle = m_sGrandparentTitle; + if (seriesTitle.empty() && m_pParent) seriesTitle = m_pParent->m_sGrandparentTitle; + grid->AddStringToken((int) (eTokenGridStr::seriestitle), seriesTitle.c_str()); + grid->AddIntToken((int) (eTokenGridInt::season), m_iParentIndex); + grid->AddIntToken((int) (eTokenGridInt::episode), m_iIndex); + + // Seriescover, Seasoncover + cached = false; + std::string grandparentthumbUri = m_sGrandparentThumb; + if (grandparentthumbUri.empty() && m_pParent) { + grandparentthumbUri = m_sThumb; + } + if (!grandparentthumbUri.empty()) { + std::string grandparentThumb = cPictureCache::GetInstance().GetPath( + m_pServer->GetUri() + grandparentthumbUri, Config::GetInstance().ThumbWidth(), + Config::GetInstance().ThumbHeight(), cached, OnCached, this); + if (cached) grid->AddStringToken((int) (eTokenGridStr::seriesthumb), grandparentThumb.c_str()); + } + grid->AddIntToken((int) (eTokenGridInt::hasseriesthumb), cached); + + // Banner, Seriesbanner + if (m_pParent && !m_pParent->m_sBanner.empty()) { + cached = false; + std::string banner = cPictureCache::GetInstance().GetPath(m_pServer->GetUri() + m_pParent->m_sBanner, + Config::GetInstance().BannerWidth(), + Config::GetInstance().BannerHeight(), cached, + OnCached, this); + if (cached) { + grid->AddIntToken((int) (eTokenGridInt::hasbanner), cached); + grid->AddStringToken((int) (eTokenGridStr::banner), banner.c_str()); + } + } + } + + m_Media.AddTokens(grid); + } + #endif -std::string cVideo::ArtUri() -{ - if(m_sArt.find("http://") != std::string::npos) return m_sArt; - if(m_sArt[0] == '/') return m_pServer->GetUri() + m_sArt; - return m_pServer->GetUri() + '/' + m_sArt; -} - -std::string cVideo::ThumbUri() -{ - if(m_sThumb.find("http://") != std::string::npos) return m_sThumb; - if(m_sThumb[0] == '/') return m_pServer->GetUri() + m_sThumb; - return m_pServer->GetUri() + '/' + m_sThumb; -} - -std::string cVideo::GetSubtitleUrl() -{ - // /video/:/transcode/universal/subtitles - // Argument? m_sKey? - //std::string subtitleUrl = m_pServer.GetUri() + "/video/:/transcode/universal/subtitles?" + Config::GetInstance().GetUUID(); - return ""; - // Format is "Mpeg4 Timed Text" -} + std::string cVideo::ArtUri() { + if (m_sArt.find("http://") != std::string::npos) return m_sArt; + if (m_sArt[0] == '/') return m_pServer->GetUri() + m_sArt; + return m_pServer->GetUri() + '/' + m_sArt; + } + + std::string cVideo::ThumbUri() { + if (m_sThumb.find("http://") != std::string::npos) return m_sThumb; + if (m_sThumb[0] == '/') return m_pServer->GetUri() + m_sThumb; + return m_pServer->GetUri() + '/' + m_sThumb; + } + + std::string cVideo::GetSubtitleUrl() { + // /video/:/transcode/universal/subtitles + // Argument? m_sKey? + //std::string subtitleUrl = m_pServer.GetUri() + "/video/:/transcode/universal/subtitles?" + Config::GetInstance().GetUUID(); + return ""; + // Format is "Mpeg4 Timed Text" + } } // Namespace @@ -17,9 +17,11 @@ #include <memory> #ifdef SKINDESIGNER - #include <libskindesignerapi/osdelements.h> - #include "viewGridNavigator.h" - #include "pictureCache.h" + +#include <libskindesignerapi/osdelements.h> +#include "viewGridNavigator.h" +#include "pictureCache.h" + #endif #include "XmlObject.h" @@ -35,79 +37,89 @@ using Poco::XML::Node; using Poco::XML::AutoPtr; using Poco::Exception; -namespace plexclient -{ -class MediaContainer; +namespace plexclient { + class MediaContainer; -class cVideo: private XmlObject + class cVideo : private XmlObject #ifdef SKINDESIGNER -,public cGridElement + , public cGridElement #endif -{ -private: - MediaContainer* m_pParent; - void Parse(Poco::XML::Node* pNode); - void ParseExtras(Poco::XML::Node* pNode); - -public: - cVideo(Poco::XML::Node* pNode, PlexServer* Server, MediaContainer* parent); - cVideo() {}; - -public: - int m_iRatingKey; - std::string m_sKey; - std::string m_sStudio; - MediaType m_tType; - std::string m_sTitle; - std::string m_sOriginalTitle; - std::string m_sGrandparentTitle; - std::string m_sContentRating; - std::string m_sSummary; - std::string m_sTagline; - long m_lViewoffset; - Poco::Timestamp m_tLastViewedAt; - int m_iYear; - std::string m_sThumb; - std::string m_sGrandparentThumb; - std::string m_sArt; - std::string m_sGrandparentArt; - long m_iDuration; - int m_iViewCount; - double m_dRating; - Poco::Timestamp m_tAddedAt; - Poco::Timestamp m_tUpdatedAt; - Poco::DateTime m_tOriginallyAvailableAt; - - std::vector<std::string> m_vGenre; - std::vector<std::string> m_vWriter; - std::vector<std::string> m_vDirector; - std::vector<std::string> m_vCountry; - std::vector<std::string> m_vRole; - std::string m_sCollection; - Media m_Media; - PlexServer* m_pServer; - int m_iMyPlayOffset; - int m_iIndex; - int m_iParentIndex; - std::vector<cVideo> m_vExtras; - ExtraType m_eExtraType; - - virtual std::string GetTitle(); - bool SetStream(Stream* stream); - bool UpdateFromServer(); - bool SetWatched(); - bool SetUnwatched(); - std::string ThumbUri(); - std::string ArtUri(); - - std::string GetSubtitleUrl(); - + { + private: + MediaContainer *m_pParent; + + void Parse(Poco::XML::Node *pNode); + + void ParseExtras(Poco::XML::Node *pNode); + + public: + cVideo(Poco::XML::Node *pNode, PlexServer *Server, MediaContainer *parent); + + cVideo() { }; + + public: + int m_iRatingKey; + std::string m_sKey; + std::string m_sStudio; + MediaType m_tType; + std::string m_sTitle; + std::string m_sOriginalTitle; + std::string m_sGrandparentTitle; + std::string m_sContentRating; + std::string m_sSummary; + std::string m_sTagline; + long m_lViewoffset; + Poco::Timestamp m_tLastViewedAt; + int m_iYear; + std::string m_sThumb; + std::string m_sGrandparentThumb; + std::string m_sArt; + std::string m_sGrandparentArt; + long m_iDuration; + int m_iViewCount; + double m_dRating; + Poco::Timestamp m_tAddedAt; + Poco::Timestamp m_tUpdatedAt; + Poco::DateTime m_tOriginallyAvailableAt; + + std::vector<std::string> m_vGenre; + std::vector<std::string> m_vWriter; + std::vector<std::string> m_vDirector; + std::vector<std::string> m_vCountry; + std::vector<std::string> m_vRole; + std::string m_sCollection; + Media m_Media; + PlexServer *m_pServer; + int m_iMyPlayOffset; + int m_iIndex; + int m_iParentIndex; + std::vector<cVideo> m_vExtras; + ExtraType m_eExtraType; + + virtual std::string GetTitle(); + + bool SetStream(Stream *stream); + + bool UpdateFromServer(); + + bool SetWatched(); + + bool SetUnwatched(); + + std::string ThumbUri(); + + std::string ArtUri(); + + std::string GetSubtitleUrl(); + #ifdef SKINDESIGNER - // gridElement - virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, std::function<void(cGridElement*)> OnCached = NULL); - + + // gridElement + virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, + std::function<void(cGridElement *)> OnCached = NULL); + #endif -}; + }; } diff --git a/PlexHTTPRequestHandler.cpp b/PlexHTTPRequestHandler.cpp index 81f0628..a157087 100644 --- a/PlexHTTPRequestHandler.cpp +++ b/PlexHTTPRequestHandler.cpp @@ -8,294 +8,285 @@ #include "hlsPlayerControl.h" #include "services.h" -namespace plexclient -{ - -void PlexHTTPRequestHandler::AddHeaders(Poco::Net::HTTPServerResponse& response, Poco::Net::HTTPServerRequest& request) -{ - if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { - response.setContentType("text/plain"); - - response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); - response.add("Connection", "Close"); - response.add("Access-Control-Max-Age", "1209600"); - response.add("Access-Control-Allow-Origin", "*"); - response.add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, HEAD"); - response.add("Access-Control-Allow-Headers", - "x-plex-version, x-plex-platform-version, " - "x-plex-username, x-plex-client-identifier, " - "x-plex-target-client-identifier, x-plex-device-name, " - "x-plex-platform, x-plex-product, accept, x-plex-device"); - } else { - response.setContentType("application/x-www-form-urlencoded"); - - response.add("Access-Control-Allow-Origin", "*"); - response.add("X-Plex-Version", VERSION); - response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); - response.add("X-Plex-Product", DESCRIPTION); - response.add("X-Plex-Device-Name", Config::GetInstance().GetHostname()); - response.add("X-Plex-Platform", "VDR"); - response.add("X-Plex-Model", "Linux"); - response.add("X-Plex-Device", "PC"); - response.add("X-Plex-Username", Config::GetInstance().GetUsername()); - } - // header.MessageHeader(header); -} - -std::map<std::string, std::string> PlexHTTPRequestHandler::ParseQuery(std::string query) -{ - std::map<std::string, std::string> querymap; - Poco::StringTokenizer queryTokens(query, "&"); - for(Poco::StringTokenizer::Iterator token = queryTokens.begin(); token != queryTokens.end(); token++) { - int pos = token->find("="); - querymap[token->substr(0, pos)] = token->substr(pos+1, std::string::npos); - } - return querymap; -} - -std::string PlexHTTPRequestHandler::GetOKMsg() -{ - return "<?xml version=\"1.0\" encoding=\"utf-8\"?> <Response code=\"200\" status=\"OK\" />"; -} - -void PlexHTTPRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response) -{ - response.send() << " "; // Stream must not be empty! - response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_NOT_FOUND); -} - -void PlexHTTPRequestHandler::UpdateCommandId(Poco::Net::HTTPServerRequest& request) -{ - Poco::URI uri(request.getURI()); - std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); // port=32400&commandID=0&protocol=http - - std::string uuid = request.get("X-Plex-Client-Identifier", ""); - if(uuid.length() != 0) { - std::string command = query["commandID"]; - SubscriptionManager::GetInstance().UpdateSubscriber(uuid, command); - } -} - -void SubscribeRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response) -{ - UpdateCommandId(request); - Poco::URI uri(request.getURI()); - std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); - - if(query.find("wait") != query.end() && atoi(query["wait"].c_str()) == 1) { - usleep(900 * 1000); - } - - if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { - AddHeaders(response, request); - response.send() << " "; // Stream must not be empty! - response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); - return; - } - - // parse query - if(request.getURI().find("/subscribe") != std::string::npos) { - Subscribe(request); - AddHeaders(response, request); - response.send() << GetOKMsg(); - response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); - } else if(request.getURI().find("/unsubscribe") != std::string::npos) { - Unsubscribe(request); - AddHeaders(response, request); - response.send() << GetOKMsg(); - response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); - } else if(request.getURI().find("/poll") != std::string::npos) { - response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); - response.add("Access-Control-Expose-Headers", "X-Plex-Client-Identifier"); - response.add("Access-Control-Allow-Origin", "*"); - response.setContentType("text/xml"); - response.send() << SubscriptionManager::GetInstance().GetMsg(query["commandID"]); - response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); - } -} - -void SubscribeRequestHandler::Subscribe(Poco::Net::HTTPServerRequest& request) -{ - Poco::URI uri(request.getURI()); - std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); // port=32400&commandID=0&protocol=http - - std::string uuid = request.get("X-Plex-Client-Identifier", ""); - if(uuid.length() != 0) { - int port = atoi(query["port"].c_str()); - std::string command = query["commandID"]; - - SubscriptionManager::GetInstance().AddSubscriber( - Subscriber(query["protocol"], request.clientAddress().host().toString(), port, uuid, command)); - } -} - -void SubscribeRequestHandler::Unsubscribe(Poco::Net::HTTPServerRequest& request) -{ - std::string uuid = request.get("X-Plex-Client-Identifier", ""); - if(uuid.length() != 0) { - SubscriptionManager::GetInstance().RemoveSubscriber(uuid); - } -} - -void ResourceRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, - Poco::Net::HTTPServerResponse& response) -{ - UpdateCommandId(request); - AddHeaders(response, request); - - std::ostream& ostr = response.send(); - ostr << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" - "<MediaContainer>" - "<Player title=\"" << Config::GetInstance().GetHostname() << "\"" - " protocol=\"plex\"" - " protocolVersion=\"1\"" - " protocolCapabilities=\"navigation,playback,timeline\"" - " machineIdentifier=\"" << Config::GetInstance().GetUUID() << "\"" - " product=\"" << DESCRIPTION << "\"" - " platform=\"Linux\"" - " platformVersion=\"" << VERSION << "\"" - " deviceClass=\"HTPC\"" - "/> </MediaContainer>"; - - response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); - - // dsyslog("[plex]Resources Response sent..."); -} - -void PlayerRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) -{ - try { - UpdateCommandId(request); - - Poco::URI uri(request.getURI()); - std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); - - if(query.find("wait") != query.end() && atoi(query["wait"].c_str()) == 1) { - usleep(900 * 1000); - } - - if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { - AddHeaders(response, request); - response.send() << " "; // Stream must not be empty! - return; - } - - if(request.getURI().find("/poll") != std::string::npos) { - response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); - response.add("Access-Control-Expose-Headers", "X-Plex-Client-Identifier"); - response.add("Access-Control-Allow-Origin", "*"); - response.setContentType("text/xml"); - std::ostream& ostr = response.send(); - ostr << SubscriptionManager::GetInstance().GetMsg(query["commandID"]); - - } else if(request.getURI().find("/navigation") != std::string::npos) { - if(request.getURI().find("/moveUp") != std::string::npos) { - cRemote::Put(kUp); - } else if(request.getURI().find("/moveDown") != std::string::npos) { - cRemote::Put(kDown); - } else if(request.getURI().find("/moveLeft") != std::string::npos) { - cRemote::Put(kLeft); - } else if(request.getURI().find("/moveRight") != std::string::npos) { - cRemote::Put(kRight); - } else if(request.getURI().find("/select") != std::string::npos) { - cRemote::Put(kOk); - } else if(request.getURI().find("/home") != std::string::npos) { - cRemote::Put(kMenu); - } else if(request.getURI().find("/back") != std::string::npos) { - cRemote::Put(kBack); - } - response.send() << GetOKMsg(); - - } else if(request.getURI().find("/playback") != std::string::npos) { - if(request.getURI().find("/playback/seekTo") != std::string::npos) { - cHlsPlayerControl* control = dynamic_cast<cHlsPlayerControl*>(cControl::Control(true)); - if(query.find("offset") != query.end()) { - int offset = atoi(query["offset"].c_str()) / 1000; - if(control) { - isyslog("[plex] Seeking to %d", offset); - control->SeekTo(offset); - } else if(cMyPlugin::PlayingFile) { - cPlugin* mpvPlugin = cPluginManager::GetPlugin("mpv"); - if(mpvPlugin) { - Mpv_Seek seekData; - seekData.SeekAbsolute = offset; - seekData.SeekRelative = 0; - mpvPlugin->Service(MPV_SEEK, &seekData); - } - } - } - } else if(request.getURI().find("/playback/playMedia") != std::string::npos) { - AddHeaders(response, request); - std::string protocol = query["protocol"]; - std::string address = query["address"]; - std::string port = query["port"]; - std::string key = query["key"]; - - std::string fullUrl = protocol + "://" + address + ":" + port + key; // Metainfo - auto Cont = Plexservice::GetMediaContainer(fullUrl); - - // Check for video - if(Cont && Cont->m_vVideos.size() > 0) { - // MUSS im Maintread des Plugins/VDR gestartet werden - if(query.find("offset") != query.end()) { - Cont->m_vVideos[0].m_iMyPlayOffset = atoi(query["offset"].c_str()) / 1000; - if(Cont->m_vVideos[0].m_iMyPlayOffset == 0) { - Cont->m_vVideos[0].m_iMyPlayOffset = -1; - } - - } - - ActionManager::GetInstance().AddAction(Cont->m_vVideos[0]); - } - } else if(request.getURI().find("/playback/play") != std::string::npos) { - cRemote::Put(kPlay); - } else if(request.getURI().find("/playback/pause") != std::string::npos) { - cRemote::Put(kPause); - } else if(request.getURI().find("/playback/stop") != std::string::npos) { - cRemote::Put(kStop); - } else if(request.getURI().find("/playback/stepForward") != std::string::npos) { - cHlsPlayerControl* control = dynamic_cast<cHlsPlayerControl*>(cControl::Control(true)); - if(control) { - control->JumpRelative(30); - } else if(cMyPlugin::PlayingFile) { - cPlugin* mpvPlugin = cPluginManager::GetPlugin("mpv"); - if(mpvPlugin) { - Mpv_Seek seekData; - seekData.SeekAbsolute = 0; - seekData.SeekRelative = 30; - mpvPlugin->Service(MPV_SEEK, &seekData); - } - } else - cRemote::Put(kFastFwd); - } else if(request.getURI().find("/playback/stepBack") != std::string::npos) { - cHlsPlayerControl* control = dynamic_cast<cHlsPlayerControl*>(cControl::Control(true)); - if(control) { - control->JumpRelative(-15); - }else if(cMyPlugin::PlayingFile) { - cPlugin* mpvPlugin = cPluginManager::GetPlugin("mpv"); - if(mpvPlugin) { - Mpv_Seek seekData; - seekData.SeekAbsolute = 0; - seekData.SeekRelative = -15; - mpvPlugin->Service(MPV_SEEK, &seekData); - } - } else - cRemote::Put(kFastRew); - } else if(request.getURI().find("/playback/skipNext") != std::string::npos) { - cRemote::Put(kFastFwd); - } else if(request.getURI().find("/playback/skipPrevious") != std::string::npos) { - cRemote::Put(kFastRew); - } - - SubscriptionManager::GetInstance().Notify(); - response.send() << GetOKMsg(); - } - - } catch(Poco::Exception& e) { - std::cerr << e.displayText() << std::endl; - } -} +namespace plexclient { + + void PlexHTTPRequestHandler::AddHeaders(Poco::Net::HTTPServerResponse &response, + Poco::Net::HTTPServerRequest &request) { + if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { + response.setContentType("text/plain"); + + response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); + response.add("Connection", "Close"); + response.add("Access-Control-Max-Age", "1209600"); + response.add("Access-Control-Allow-Origin", "*"); + response.add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, HEAD"); + response.add("Access-Control-Allow-Headers", + "x-plex-version, x-plex-platform-version, " + "x-plex-username, x-plex-client-identifier, " + "x-plex-target-client-identifier, x-plex-device-name, " + "x-plex-platform, x-plex-product, accept, x-plex-device"); + } else { + response.setContentType("application/x-www-form-urlencoded"); + + response.add("Access-Control-Allow-Origin", "*"); + response.add("X-Plex-Version", VERSION); + response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); + response.add("X-Plex-Product", DESCRIPTION); + response.add("X-Plex-Device-Name", Config::GetInstance().GetHostname()); + response.add("X-Plex-Platform", "VDR"); + response.add("X-Plex-Model", "Linux"); + response.add("X-Plex-Device", "PC"); + response.add("X-Plex-Username", Config::GetInstance().GetUsername()); + } + // header.MessageHeader(header); + } + + std::map<std::string, std::string> PlexHTTPRequestHandler::ParseQuery(std::string query) { + std::map<std::string, std::string> querymap; + Poco::StringTokenizer queryTokens(query, "&"); + for (Poco::StringTokenizer::Iterator token = queryTokens.begin(); token != queryTokens.end(); token++) { + int pos = token->find("="); + querymap[token->substr(0, pos)] = token->substr(pos + 1, std::string::npos); + } + return querymap; + } + + std::string PlexHTTPRequestHandler::GetOKMsg() { + return "<?xml version=\"1.0\" encoding=\"utf-8\"?> <Response code=\"200\" status=\"OK\" />"; + } + + void PlexHTTPRequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request, + Poco::Net::HTTPServerResponse &response) { + response.send() << " "; // Stream must not be empty! + response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_NOT_FOUND); + } + + void PlexHTTPRequestHandler::UpdateCommandId(Poco::Net::HTTPServerRequest &request) { + Poco::URI uri(request.getURI()); + std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); // port=32400&commandID=0&protocol=http + + std::string uuid = request.get("X-Plex-Client-Identifier", ""); + if (uuid.length() != 0) { + std::string command = query["commandID"]; + SubscriptionManager::GetInstance().UpdateSubscriber(uuid, command); + } + } + + void SubscribeRequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request, + Poco::Net::HTTPServerResponse &response) { + UpdateCommandId(request); + Poco::URI uri(request.getURI()); + std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); + + if (query.find("wait") != query.end() && atoi(query["wait"].c_str()) == 1) { + usleep(900 * 1000); + } + + if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { + AddHeaders(response, request); + response.send() << " "; // Stream must not be empty! + response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); + return; + } + + // parse query + if (request.getURI().find("/subscribe") != std::string::npos) { + Subscribe(request); + AddHeaders(response, request); + response.send() << GetOKMsg(); + response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); + } else if (request.getURI().find("/unsubscribe") != std::string::npos) { + Unsubscribe(request); + AddHeaders(response, request); + response.send() << GetOKMsg(); + response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); + } else if (request.getURI().find("/poll") != std::string::npos) { + response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); + response.add("Access-Control-Expose-Headers", "X-Plex-Client-Identifier"); + response.add("Access-Control-Allow-Origin", "*"); + response.setContentType("text/xml"); + response.send() << SubscriptionManager::GetInstance().GetMsg(query["commandID"]); + response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); + } + } + + void SubscribeRequestHandler::Subscribe(Poco::Net::HTTPServerRequest &request) { + Poco::URI uri(request.getURI()); + std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); // port=32400&commandID=0&protocol=http + + std::string uuid = request.get("X-Plex-Client-Identifier", ""); + if (uuid.length() != 0) { + int port = atoi(query["port"].c_str()); + std::string command = query["commandID"]; + + SubscriptionManager::GetInstance().AddSubscriber( + Subscriber(query["protocol"], request.clientAddress().host().toString(), port, uuid, command)); + } + } + + void SubscribeRequestHandler::Unsubscribe(Poco::Net::HTTPServerRequest &request) { + std::string uuid = request.get("X-Plex-Client-Identifier", ""); + if (uuid.length() != 0) { + SubscriptionManager::GetInstance().RemoveSubscriber(uuid); + } + } + + void ResourceRequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request, + Poco::Net::HTTPServerResponse &response) { + UpdateCommandId(request); + AddHeaders(response, request); + + std::ostream &ostr = response.send(); + ostr << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<MediaContainer>" + "<Player title=\"" << Config::GetInstance().GetHostname() << "\"" + " protocol=\"plex\"" + " protocolVersion=\"1\"" + " protocolCapabilities=\"navigation,playback,timeline\"" + " machineIdentifier=\"" << Config::GetInstance().GetUUID() << "\"" + " product=\"" << DESCRIPTION << "\"" + " platform=\"Linux\"" + " platformVersion=\"" << VERSION << "\"" + " deviceClass=\"HTPC\"" + "/> </MediaContainer>"; + + response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK); + + // dsyslog("[plex]Resources Response sent..."); + } + + void PlayerRequestHandler::handleRequest(Poco::Net::HTTPServerRequest &request, + Poco::Net::HTTPServerResponse &response) { + try { + UpdateCommandId(request); + + Poco::URI uri(request.getURI()); + std::map<std::string, std::string> query = ParseQuery(uri.getQuery()); + + if (query.find("wait") != query.end() && atoi(query["wait"].c_str()) == 1) { + usleep(900 * 1000); + } + + if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { + AddHeaders(response, request); + response.send() << " "; // Stream must not be empty! + return; + } + + if (request.getURI().find("/poll") != std::string::npos) { + response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); + response.add("Access-Control-Expose-Headers", "X-Plex-Client-Identifier"); + response.add("Access-Control-Allow-Origin", "*"); + response.setContentType("text/xml"); + std::ostream &ostr = response.send(); + ostr << SubscriptionManager::GetInstance().GetMsg(query["commandID"]); + + } else if (request.getURI().find("/navigation") != std::string::npos) { + if (request.getURI().find("/moveUp") != std::string::npos) { + cRemote::Put(kUp); + } else if (request.getURI().find("/moveDown") != std::string::npos) { + cRemote::Put(kDown); + } else if (request.getURI().find("/moveLeft") != std::string::npos) { + cRemote::Put(kLeft); + } else if (request.getURI().find("/moveRight") != std::string::npos) { + cRemote::Put(kRight); + } else if (request.getURI().find("/select") != std::string::npos) { + cRemote::Put(kOk); + } else if (request.getURI().find("/home") != std::string::npos) { + cRemote::Put(kMenu); + } else if (request.getURI().find("/back") != std::string::npos) { + cRemote::Put(kBack); + } + response.send() << GetOKMsg(); + + } else if (request.getURI().find("/playback") != std::string::npos) { + if (request.getURI().find("/playback/seekTo") != std::string::npos) { + cHlsPlayerControl *control = dynamic_cast<cHlsPlayerControl *>(cControl::Control(true)); + if (query.find("offset") != query.end()) { + int offset = atoi(query["offset"].c_str()) / 1000; + if (control) { + isyslog("[plex] Seeking to %d", offset); + control->SeekTo(offset); + } else if (cMyPlugin::PlayingFile) { + cPlugin *mpvPlugin = cPluginManager::GetPlugin("mpv"); + if (mpvPlugin) { + Mpv_Seek seekData; + seekData.SeekAbsolute = offset; + seekData.SeekRelative = 0; + mpvPlugin->Service(MPV_SEEK, &seekData); + } + } + } + } else if (request.getURI().find("/playback/playMedia") != std::string::npos) { + AddHeaders(response, request); + std::string protocol = query["protocol"]; + std::string address = query["address"]; + std::string port = query["port"]; + std::string key = query["key"]; + + std::string fullUrl = protocol + "://" + address + ":" + port + key; // Metainfo + auto Cont = Plexservice::GetMediaContainer(fullUrl); + + // Check for video + if (Cont && Cont->m_vVideos.size() > 0) { + // MUSS im Maintread des Plugins/VDR gestartet werden + if (query.find("offset") != query.end()) { + Cont->m_vVideos[0].m_iMyPlayOffset = atoi(query["offset"].c_str()) / 1000; + if (Cont->m_vVideos[0].m_iMyPlayOffset == 0) { + Cont->m_vVideos[0].m_iMyPlayOffset = -1; + } + + } + + ActionManager::GetInstance().AddAction(Cont->m_vVideos[0]); + } + } else if (request.getURI().find("/playback/play") != std::string::npos) { + cRemote::Put(kPlay); + } else if (request.getURI().find("/playback/pause") != std::string::npos) { + cRemote::Put(kPause); + } else if (request.getURI().find("/playback/stop") != std::string::npos) { + cRemote::Put(kStop); + } else if (request.getURI().find("/playback/stepForward") != std::string::npos) { + cHlsPlayerControl *control = dynamic_cast<cHlsPlayerControl *>(cControl::Control(true)); + if (control) { + control->JumpRelative(30); + } else if (cMyPlugin::PlayingFile) { + cPlugin *mpvPlugin = cPluginManager::GetPlugin("mpv"); + if (mpvPlugin) { + Mpv_Seek seekData; + seekData.SeekAbsolute = 0; + seekData.SeekRelative = 30; + mpvPlugin->Service(MPV_SEEK, &seekData); + } + } else + cRemote::Put(kFastFwd); + } else if (request.getURI().find("/playback/stepBack") != std::string::npos) { + cHlsPlayerControl *control = dynamic_cast<cHlsPlayerControl *>(cControl::Control(true)); + if (control) { + control->JumpRelative(-15); + } else if (cMyPlugin::PlayingFile) { + cPlugin *mpvPlugin = cPluginManager::GetPlugin("mpv"); + if (mpvPlugin) { + Mpv_Seek seekData; + seekData.SeekAbsolute = 0; + seekData.SeekRelative = -15; + mpvPlugin->Service(MPV_SEEK, &seekData); + } + } else + cRemote::Put(kFastRew); + } else if (request.getURI().find("/playback/skipNext") != std::string::npos) { + cRemote::Put(kFastFwd); + } else if (request.getURI().find("/playback/skipPrevious") != std::string::npos) { + cRemote::Put(kFastRew); + } + + SubscriptionManager::GetInstance().Notify(); + response.send() << GetOKMsg(); + } + + } catch (Poco::Exception &e) { + std::cerr << e.displayText() << std::endl; + } + } } // namespace diff --git a/PlexHTTPRequestHandler.h b/PlexHTTPRequestHandler.h index 2787e18..9f0d69f 100644 --- a/PlexHTTPRequestHandler.h +++ b/PlexHTTPRequestHandler.h @@ -23,41 +23,40 @@ #include "plexgdm.h" +namespace plexclient { -namespace plexclient -{ - -class PlexHTTPRequestHandler : public Poco::Net::HTTPRequestHandler -{ -public: - virtual void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); - -protected: - std::string GetOKMsg(); - void AddHeaders(Poco::Net::HTTPServerResponse& response, Poco::Net::HTTPServerRequest& request); - std::map<std::string, std::string> ParseQuery(std::string query); - void UpdateCommandId(Poco::Net::HTTPServerRequest& request); -}; - -class SubscribeRequestHandler : public PlexHTTPRequestHandler -{ -public: - virtual void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); - void Subscribe(Poco::Net::HTTPServerRequest& request); - void Unsubscribe(Poco::Net::HTTPServerRequest& request); -}; - -class ResourceRequestHandler : public PlexHTTPRequestHandler -{ -public: - virtual void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); -}; - -class PlayerRequestHandler : public PlexHTTPRequestHandler -{ -public: - virtual void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); -}; + class PlexHTTPRequestHandler : public Poco::Net::HTTPRequestHandler { + public: + virtual void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response); + + protected: + std::string GetOKMsg(); + + void AddHeaders(Poco::Net::HTTPServerResponse &response, Poco::Net::HTTPServerRequest &request); + + std::map<std::string, std::string> ParseQuery(std::string query); + + void UpdateCommandId(Poco::Net::HTTPServerRequest &request); + }; + + class SubscribeRequestHandler : public PlexHTTPRequestHandler { + public: + virtual void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response); + + void Subscribe(Poco::Net::HTTPServerRequest &request); + + void Unsubscribe(Poco::Net::HTTPServerRequest &request); + }; + + class ResourceRequestHandler : public PlexHTTPRequestHandler { + public: + virtual void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response); + }; + + class PlayerRequestHandler : public PlexHTTPRequestHandler { + public: + virtual void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response); + }; } diff --git a/PlexHelper.cpp b/PlexHelper.cpp index 61643d7..97bb7fa 100644 --- a/PlexHelper.cpp +++ b/PlexHelper.cpp @@ -2,24 +2,23 @@ #include "Config.h" #include "plex.h" -namespace plexclient -{ +namespace plexclient { -void PlexHelper::AddHttpHeader(Poco::Net::HTTPRequest& request) -{ - request.add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17"); + void PlexHelper::AddHttpHeader(Poco::Net::HTTPRequest &request) { + request.add("User-Agent", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17"); - //request.add("X-Plex-Client-Capabilities", "protocols=shoutcast,http-video;videoDecoders=h264{profile:high&resolution:1080&level:51};audioDecoders=mp3,aac"); - request.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); - request.add("X-Plex-Device", "PC"); - request.add("X-Plex-Device-Name", Config::GetInstance().GetHostname()); - request.add("X-Plex-Language", Config::GetInstance().GetLanguage()); - request.add("X-Plex-Model", "Linux"); - request.add("X-Plex-Platform", "VDR"); - request.add("X-Plex-Product", "plex for vdr"); - request.add("X-Plex-Provides", "player"); - request.add("X-Plex-Version", VERSION); -} + //request.add("X-Plex-Client-Capabilities", "protocols=shoutcast,http-video;videoDecoders=h264{profile:high&resolution:1080&level:51};audioDecoders=mp3,aac"); + request.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); + request.add("X-Plex-Device", "PC"); + request.add("X-Plex-Device-Name", Config::GetInstance().GetHostname()); + request.add("X-Plex-Language", Config::GetInstance().GetLanguage()); + request.add("X-Plex-Model", "Linux"); + request.add("X-Plex-Platform", "VDR"); + request.add("X-Plex-Product", "plex for vdr"); + request.add("X-Plex-Provides", "player"); + request.add("X-Plex-Version", VERSION); + } } // namespace diff --git a/PlexHelper.h b/PlexHelper.h index 0df6eaf..3c77987 100644 --- a/PlexHelper.h +++ b/PlexHelper.h @@ -3,17 +3,16 @@ #include <Poco/Net/HTTPRequest.h> -namespace plexclient -{ +namespace plexclient { -class PlexHelper -{ -public: - static void AddHttpHeader(Poco::Net::HTTPRequest& request); -private: - PlexHelper() {}; + class PlexHelper { + public: + static void AddHttpHeader(Poco::Net::HTTPRequest &request); -}; + private: + PlexHelper() { }; + + }; } diff --git a/PlexReqHandlerFactory.cpp b/PlexReqHandlerFactory.cpp index dacdff7..c1d9401 100644 --- a/PlexReqHandlerFactory.cpp +++ b/PlexReqHandlerFactory.cpp @@ -1,18 +1,15 @@ #include "PlexReqHandlerFactory.h" -namespace plexclient -{ +namespace plexclient { -PlexReqHandlerFactory::PlexReqHandlerFactory() -{ -} + PlexReqHandlerFactory::PlexReqHandlerFactory() { + } -PlexReqHandlerFactory::~PlexReqHandlerFactory() -{ -} + PlexReqHandlerFactory::~PlexReqHandlerFactory() { + } -Poco::Net::HTTPRequestHandler* PlexReqHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) -{ /* + Poco::Net::HTTPRequestHandler *PlexReqHandlerFactory::createRequestHandler( + const Poco::Net::HTTPServerRequest &request) { /* if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) { std::cout << "GET Request: " << request.getURI() << " from: " << request.clientAddress().toString() << std::endl; } else if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) { @@ -24,11 +21,11 @@ Poco::Net::HTTPRequestHandler* PlexReqHandlerFactory::createRequestHandler(const std::cout << "??? Request: " << request.getURI() << " from: " << request.clientAddress().toString() << std::endl; } */ - if(request.getURI().find("/player/timeline")!= std::string::npos) return new SubscribeRequestHandler(); - else if(request.getURI().find("/resources")!= std::string::npos) return new ResourceRequestHandler(); - else if(request.getURI().find("/player")!= std::string::npos) return new PlayerRequestHandler(); + if (request.getURI().find("/player/timeline") != std::string::npos) return new SubscribeRequestHandler(); + else if (request.getURI().find("/resources") != std::string::npos) return new ResourceRequestHandler(); + else if (request.getURI().find("/player") != std::string::npos) return new PlayerRequestHandler(); - return new PlexHTTPRequestHandler(); -} + return new PlexHTTPRequestHandler(); + } } diff --git a/PlexReqHandlerFactory.h b/PlexReqHandlerFactory.h index 82ceb8a..15c97ef 100644 --- a/PlexReqHandlerFactory.h +++ b/PlexReqHandlerFactory.h @@ -9,18 +9,17 @@ #include "Config.h" -namespace plexclient -{ - -class PlexReqHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory -{ -public: - PlexReqHandlerFactory(); - ~PlexReqHandlerFactory(); - -public: - virtual Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request); -}; +namespace plexclient { + + class PlexReqHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { + public: + PlexReqHandlerFactory(); + + ~PlexReqHandlerFactory(); + + public: + virtual Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &request); + }; } diff --git a/PlexServer.cpp b/PlexServer.cpp index 42db999..8e49805 100644 --- a/PlexServer.cpp +++ b/PlexServer.cpp @@ -3,149 +3,142 @@ #include "Config.h" #include "plex.h" -namespace plexclient -{ - -PlexServer::PlexServer(std::string ip, int port) -{ - Poco::URI uri; - uri.setHost(ip); - uri.setPort(port); - uri.setScheme("http"); - m_uri = uri.toString(); - Offline = false; -} +namespace plexclient { -PlexServer::PlexServer(std::string data, std::string ip) -{ - ParseData(data, ip); -} + PlexServer::PlexServer(std::string ip, int port) { + Poco::URI uri; + uri.setHost(ip); + uri.setPort(port); + uri.setScheme("http"); + m_uri = uri.toString(); + Offline = false; + } -PlexServer::PlexServer(std::string uri, std::string name, std::string uuid, std::string accessToken, bool owned, bool local) -{ - m_sServerName = name; - m_sUuid = uuid; - m_nOwned = owned; - m_bLocal = local; - m_authToken = accessToken; - Offline = false; - m_uri = uri; -} + PlexServer::PlexServer(std::string data, std::string ip) { + ParseData(data, ip); + } -PlexServer::~PlexServer() -{ - -} + PlexServer::PlexServer(std::string uri, std::string name, std::string uuid, std::string accessToken, bool owned, + bool local) { + m_sServerName = name; + m_sUuid = uuid; + m_nOwned = owned; + m_bLocal = local; + m_authToken = accessToken; + Offline = false; + m_uri = uri; + } -void PlexServer::ParseData(std::string data, std::string ip) -{ - int port = 0; - std::istringstream f(data); - std::string s; - Offline = false; - while(std::getline(f, s)) { - int pos = s.find(':'); - if(pos > 0) { - std::string name = Poco::trim(s.substr(0, pos)); - std::string val = Poco::trim(s.substr(pos+1)); - if(name == "Content-Type") { - m_sContentType = val; - } else if (name == "Resource-Identifier") { - m_sUuid = val; - } else if (name == "Name") { - m_sServerName = val; - } else if (name == "Port") { - port = atoi(val.c_str()); - } else if (name == "Updated-At") { - m_nUpdated = atol(val.c_str()); - } else if (name == "Version") { - m_sVersion = val; - } - } - } - - m_bLocal = true; - - Poco::URI uri; - - uri.setHost(ip); - uri.setPort(port); - uri.setScheme("http"); - - m_uri = uri.toString(); -} + PlexServer::~PlexServer() { -std::string PlexServer::GetHost() -{ - Poco::URI uri(m_uri); - return uri.getHost(); -} + } -int PlexServer::GetPort() -{ - Poco::URI uri(m_uri); - return uri.getPort(); -} + void PlexServer::ParseData(std::string data, std::string ip) { + int port = 0; + std::istringstream f(data); + std::string s; + Offline = false; + while (std::getline(f, s)) { + int pos = s.find(':'); + if (pos > 0) { + std::string name = Poco::trim(s.substr(0, pos)); + std::string val = Poco::trim(s.substr(pos + 1)); + if (name == "Content-Type") { + m_sContentType = val; + } else if (name == "Resource-Identifier") { + m_sUuid = val; + } else if (name == "Name") { + m_sServerName = val; + } else if (name == "Port") { + port = atoi(val.c_str()); + } else if (name == "Updated-At") { + m_nUpdated = atol(val.c_str()); + } else if (name == "Version") { + m_sVersion = val; + } + } + } -std::shared_ptr<Poco::Net::HTTPClientSession> PlexServer::GetClientSession() -{ - Poco::URI uri(m_uri); - std::shared_ptr<Poco::Net::HTTPClientSession> pHttpSession = nullptr; - if(uri.getScheme().find("https") != std::string::npos) { - pHttpSession = std::make_shared<Poco::Net::HTTPSClientSession>(uri.getHost(), uri.getPort()); - } - else { - pHttpSession = std::make_shared<Poco::Net::HTTPClientSession>(uri.getHost(), uri.getPort()); - } - - //pHttpSession->setTimeout(Poco::Timespan(5, 0)); // set 5 seconds Timeout - return pHttpSession; -} + m_bLocal = true; -std::shared_ptr<Poco::Net::HTTPClientSession> PlexServer::MakeRequest(bool& ok, std::string path, const std::map<std::string, std::string>& queryParameters) -{ - Poco::URI uri(path); - // Create a request with an optional query - if(queryParameters.size()) { - for (auto const& pair : queryParameters) { - // addQueryParameter does the encode already - uri.addQueryParameter(pair.first, pair.second); - } - } - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, uri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); - - request.add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17"); - request.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); - request.add("X-Plex-Device", "PC"); - request.add("X-Plex-Device-Name", Config::GetInstance().GetHostname()); - request.add("X-Plex-Language", Config::GetInstance().GetLanguage()); - request.add("X-Plex-Model", "Linux"); - request.add("X-Plex-Platform", "VDR"); - request.add("X-Plex-Product", "plex for vdr"); - request.add("X-Plex-Provides", "player"); - request.add("X-Plex-Version", VERSION); - - if(Config::GetInstance().UsePlexAccount && !GetAuthToken().empty()) { - // Add PlexToken to Header - request.add("X-Plex-Token", GetAuthToken()); - } - auto cSession = GetClientSession(); - ok = true; - try { - cSession->sendRequest(request); - } catch (Poco::TimeoutException &exc) { - esyslog("[plex] Timeout: %s", path.c_str()); - ok = false; - } catch (Poco::Exception &exc) { - esyslog("[plex] Oops Exception: %s", exc.displayText().c_str()); - ok = false; - } - return cSession; -} + Poco::URI uri; -std::string PlexServer::GetUri() -{ - return m_uri; -} + uri.setHost(ip); + uri.setPort(port); + uri.setScheme("http"); + + m_uri = uri.toString(); + } + + std::string PlexServer::GetHost() { + Poco::URI uri(m_uri); + return uri.getHost(); + } + + int PlexServer::GetPort() { + Poco::URI uri(m_uri); + return uri.getPort(); + } + + std::shared_ptr<Poco::Net::HTTPClientSession> PlexServer::GetClientSession() { + Poco::URI uri(m_uri); + std::shared_ptr<Poco::Net::HTTPClientSession> pHttpSession = nullptr; + if (uri.getScheme().find("https") != std::string::npos) { + pHttpSession = std::make_shared<Poco::Net::HTTPSClientSession>(uri.getHost(), uri.getPort()); + } + else { + pHttpSession = std::make_shared<Poco::Net::HTTPClientSession>(uri.getHost(), uri.getPort()); + } + + //pHttpSession->setTimeout(Poco::Timespan(5, 0)); // set 5 seconds Timeout + return pHttpSession; + } + + std::shared_ptr<Poco::Net::HTTPClientSession> PlexServer::MakeRequest(bool &ok, std::string path, + const std::map<std::string, std::string> &queryParameters) { + Poco::URI uri(path); + // Create a request with an optional query + if (queryParameters.size()) { + for (auto const &pair : queryParameters) { + // addQueryParameter does the encode already + uri.addQueryParameter(pair.first, pair.second); + } + } + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, uri.getPathAndQuery(), + Poco::Net::HTTPMessage::HTTP_1_1); + + request.add("User-Agent", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17"); + request.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); + request.add("X-Plex-Device", "PC"); + request.add("X-Plex-Device-Name", Config::GetInstance().GetHostname()); + request.add("X-Plex-Language", Config::GetInstance().GetLanguage()); + request.add("X-Plex-Model", "Linux"); + request.add("X-Plex-Platform", "VDR"); + request.add("X-Plex-Product", "plex for vdr"); + request.add("X-Plex-Provides", "player"); + request.add("X-Plex-Version", VERSION); + + if (Config::GetInstance().UsePlexAccount && !GetAuthToken().empty()) { + // Add PlexToken to Header + request.add("X-Plex-Token", GetAuthToken()); + } + auto cSession = GetClientSession(); + ok = true; + try { + cSession->sendRequest(request); + } catch (Poco::TimeoutException &exc) { + esyslog("[plex] Timeout: %s", path.c_str()); + ok = false; + } catch (Poco::Exception &exc) { + esyslog("[plex] Oops Exception: %s", exc.displayText().c_str()); + ok = false; + } + return cSession; + } + + std::string PlexServer::GetUri() { + return m_uri; + } } diff --git a/PlexServer.h b/PlexServer.h index 273df28..7bacb1b 100644 --- a/PlexServer.h +++ b/PlexServer.h @@ -17,88 +17,102 @@ #include <Poco/Net/MessageHeader.h> #include <Poco/URI.h> -namespace plexclient -{ - -class PlexServer -{ - friend class plexgdm; - - public: - PlexServer(std::string uri, std::string name, std::string uuid, std::string accessToken, bool owned, bool local); - ~PlexServer(); - - int GetMaster() const { - return m_nMaster; - } - - int IsOwned() const { - return m_nOwned; - } - const std::string& GetContentType() const { - return m_sContentType; - } - const std::string& GetDiscovery() const { - return m_sDiscovery; - } - const std::string& GetRole() const { - return m_sRole; - } - const std::string& GetServerName() const { - return m_sServerName; - } - long GetUpdated() const { - return m_nUpdated; - } - const std::string& GetUuid() const { - return m_sUuid; - } - const std::string& GetVersion() const { - return m_sVersion; - } - const std::string& GetAuthToken() const { - return m_authToken; - } - const bool& IsLocal() const { - return m_bLocal; - } - void SetAuthToken(std::string token) { - m_authToken = token; - } - - std::shared_ptr<Poco::Net::HTTPClientSession> MakeRequest(bool& ok, std::string path, const std::map<std::string, std::string>& queryParameters = std::map<std::string, std::string>()); - - std::string GetHost(); - int GetPort(); - - std::string GetUri(); - - std::shared_ptr<Poco::Net::HTTPClientSession> GetClientSession(); - - bool Offline; - -protected: - PlexServer(std::string data, std::string ip); - PlexServer(std::string ip, int port); - PlexServer() {}; - - void ParseData(std::string data, std::string ip); - -private: - std::string m_sDiscovery; - - int m_nOwned; - bool m_bLocal; - int m_nMaster; - std::string m_sRole; - std::string m_sContentType; - std::string m_sUuid; - std::string m_sServerName; - std::string m_uri; - std::string m_authToken; - long m_nUpdated; - std::string m_sVersion; -}; +namespace plexclient { + + class PlexServer { + friend class plexgdm; + + public: + PlexServer(std::string uri, std::string name, std::string uuid, std::string accessToken, bool owned, + bool local); + + ~PlexServer(); + + int GetMaster() const { + return m_nMaster; + } + + int IsOwned() const { + return m_nOwned; + } + + const std::string &GetContentType() const { + return m_sContentType; + } + + const std::string &GetDiscovery() const { + return m_sDiscovery; + } + + const std::string &GetRole() const { + return m_sRole; + } + + const std::string &GetServerName() const { + return m_sServerName; + } + + long GetUpdated() const { + return m_nUpdated; + } + + const std::string &GetUuid() const { + return m_sUuid; + } + + const std::string &GetVersion() const { + return m_sVersion; + } + + const std::string &GetAuthToken() const { + return m_authToken; + } + + const bool &IsLocal() const { + return m_bLocal; + } + + void SetAuthToken(std::string token) { + m_authToken = token; + } + + std::shared_ptr<Poco::Net::HTTPClientSession> MakeRequest(bool &ok, std::string path, + const std::map<std::string, std::string> &queryParameters = std::map<std::string, std::string>()); + + std::string GetHost(); + + int GetPort(); + + std::string GetUri(); + + std::shared_ptr<Poco::Net::HTTPClientSession> GetClientSession(); + + bool Offline; + + protected: + PlexServer(std::string data, std::string ip); + + PlexServer(std::string ip, int port); + + PlexServer() { }; + + void ParseData(std::string data, std::string ip); + + private: + std::string m_sDiscovery; + + int m_nOwned; + bool m_bLocal; + int m_nMaster; + std::string m_sRole; + std::string m_sContentType; + std::string m_sUuid; + std::string m_sServerName; + std::string m_uri; + std::string m_authToken; + long m_nUpdated; + std::string m_sVersion; + }; } #endif // PLEXSERVER_H diff --git a/Plexservice.cpp b/Plexservice.cpp index 1e76bef..9ddc29d 100644 --- a/Plexservice.cpp +++ b/Plexservice.cpp @@ -5,305 +5,302 @@ #include <memory> #include <Poco/Net/NetException.h> -namespace plexclient -{ - -Plexservice::Plexservice(PlexServer *server) -{ - pServer = server; -} - -Plexservice::Plexservice(PlexServer *server, std::string startUri) -{ - pServer = server; - StartUri = startUri; -} - -std::string Plexservice::GetMyPlexToken() -{ - static bool done; - static std::string myToken; - - //todo: cache token in file or db - if(!done) { - std::stringstream ss; - Poco::Base64Encoder b64(ss); - - b64 << Config::GetInstance().GetUsername() << ":" << Config::GetInstance().GetPassword(); - - b64.close(); - std::string tempToken = ss.str(); - - - try { - Poco::Net::HTTPSClientSession plexSession("plex.tv", 443); - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/users/sign_in.xml", Poco::Net::HTTPMessage::HTTP_1_1); - - PlexHelper::AddHttpHeader(request); - request.add("Authorization", Poco::format("Basic %s", tempToken)); - - plexSession.sendRequest(request); - - Poco::Net::HTTPResponse response; - std::istream &rs = plexSession.receiveResponse(response); - if(response.getStatus() == 201) { - // parse the XML Response - user u(&rs); - myToken = u.authenticationToken; - isyslog("[plex] plex.tv login successfull."); - } else { - esyslog("[plex] plex.tv Login failed, check you creditials."); - } - done = true; - plexSession.abort(); - } catch (Poco::Exception &exc) { - esyslog("[plex]Exception in %s s%", __func__, exc.displayText().c_str() ); - done = true; - } - - } - return myToken; -} - -void Plexservice::Authenticate() -{ - if(!Config::GetInstance().UsePlexAccount) return; - try { - std::string token = GetMyPlexToken(); - auto pRequest = CreateRequest("/?X-Plex-Token=" + token); - - Poco::Net::HTTPClientSession session(pServer->GetHost(), pServer->GetPort()); - session.sendRequest(*pRequest); - Poco::Net::HTTPResponse response; - /*std::istream &rs = */ - session.receiveResponse(response); - session.abort(); - // TODO: process response - //Poco::StreamCopier::copyStream(rs, std::cout); - } catch (Poco::Exception &exc) { - esyslog("[plex]Exception in %s s%", __func__, exc.displayText().c_str() ); - } -} - -void Plexservice::UpdateResources() -{ - // We must be autenticated - // https://plex.tv/api/resources?includeHttps=1 - if(!Config::GetInstance().UsePlexAccount) { - isyslog("[plex] To access remote servers, please login with your plex.tv account."); - return; // Plugin is used without plex.tv login - } - isyslog("[plex] Updating remote resources..."); - - - std::shared_ptr<MediaContainer> pContainer = nullptr; - try { - Poco::URI fileuri("https://plex.tv/api/resources?includeHttps=1"); - - Poco::Net::HTTPSClientSession session(fileuri.getHost(), 443); - - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); - PlexHelper::AddHttpHeader(request); - request.add("X-Plex-Token", GetMyPlexToken() ); - - session.sendRequest(request); - Poco::Net::HTTPResponse response; - std::istream &rs = session.receiveResponse(response); - - //Poco::StreamCopier::copyStream(rs, std::cout); - - pContainer = std::shared_ptr<MediaContainer>(new MediaContainer(&rs)); - - } catch (Poco::Net::NetException &exc) { - esyslog("[plex] UpdateResources, NetException: %s", exc.displayText().c_str()); - return; - } catch (Poco::Exception &exc) { - esyslog("[plex] UpdateResources, Exception: %s", exc.displayText().c_str()); - return; - } - - for(std::vector<Device>::iterator d_it = pContainer->m_vDevices.begin(); d_it != pContainer->m_vDevices.end(); ++d_it) { - - // check device is a server - if(d_it->m_sProvides.find("server") != std::string::npos) { - // is it a remote server? - if(d_it->m_bPublicAddressMatches == false) { - // pick remote connection - for(std::vector<Connection>::iterator c_it = d_it->m_vConnections.begin(); c_it != d_it->m_vConnections.end(); ++c_it) { - if(c_it->m_bLocal == false) { - dsyslog("[plex] Found server via plex.tv: %s", d_it->m_sName.c_str()); - // a remote Server - plexgdm::GetInstance().AddServer(PlexServer(c_it->m_sUri, d_it->m_sName, d_it->m_sClientIdentifier, d_it->m_sAccessToken, d_it->m_bOwned, c_it->m_bLocal)); - } - } - } - } - } -} - -PlexServer* Plexservice::GetServer() -{ - return pServer; -} - -std::shared_ptr<MediaContainer> Plexservice::GetSection(std::string section, bool putOnStack) -{ - try { - std::string uri; - if(section[0]=='/') { // Full URI? - uri = section; - } else { - uri = Poco::format("%s/%s", m_vUriStack.top(), section); - } - - if(putOnStack) { - m_vUriStack.push(uri); - } - - dsyslog("[plex] URI: %s%s", pServer->GetUri().c_str(), uri.c_str()); - - bool ok; - auto cSession = pServer->MakeRequest(ok, uri); - Poco::Net::HTTPResponse response; - std::istream& rs = cSession->receiveResponse(response); - if(ok && response.getStatus() == 200) { - std::shared_ptr<MediaContainer> pAllsections(new MediaContainer(&rs, pServer)); - return pAllsections; - } - else { - dsyslog("[plex] URI: %s%s Response bad: s%", pServer->GetUri().c_str(), uri.c_str(), response.getReasonForStatus(response.getStatus()).c_str() ); - return 0; - } - - - } catch (Poco::Net::NetException &exc) { - pServer->Offline = true; - return 0; - } -} - -std::shared_ptr<MediaContainer> Plexservice::GetLastSection(bool current) -{ - if(m_vUriStack.size() > 1) { - if(!current) { - // discard last one - m_vUriStack.pop(); - } - std::string uri = m_vUriStack.top(); - return GetSection(uri, false); - } - return NULL; -} - -bool Plexservice::IsRoot() -{ - return m_vUriStack.size() <= 1; -} - -std::unique_ptr<Poco::Net::HTTPRequest> Plexservice::CreateRequest(std::string path) -{ - std::unique_ptr<Poco::Net::HTTPRequest> pRequest = std::unique_ptr<Poco::Net::HTTPRequest>(new Poco::Net::HTTPRequest(Poco::Net::HTTPRequest::HTTP_GET, - path, Poco::Net::HTTPMessage::HTTP_1_1)); - - PlexHelper::AddHttpHeader(*pRequest); - - if(Config::GetInstance().UsePlexAccount) { - // Add PlexToken to Header - std::string token = GetMyPlexToken(); - if(pServer && !pServer->GetAuthToken().empty()) { - pRequest->add("X-Plex-Token", pServer->GetAuthToken()); - dsyslog("[plex] Using server access token"); - } else if(!token.empty()) { - pRequest->add("X-Plex-Token", token); - dsyslog("[plex] Using global access token"); - } - } - - return pRequest; -} - -std::shared_ptr<MediaContainer> Plexservice::GetMediaContainer(std::string fullUrl) -{ - PlexServer* pServer = NULL; - try { - Poco::URI fileuri(fullUrl); - dsyslog("[plex] GetMediaContainer: %s", fullUrl.c_str()); - - pServer = plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()); - - bool ok; - auto cSession = pServer->MakeRequest(ok, fileuri.getPathAndQuery()); - Poco::Net::HTTPResponse response; - std::istream &rs = cSession->receiveResponse(response); - if(ok && response.getStatus() == 200) { - std::shared_ptr<MediaContainer> pAllsections = std::shared_ptr<MediaContainer>(new MediaContainer(&rs, pServer)); - return pAllsections; - } - return 0; - //Poco::StreamCopier::copyStream(rs, std::cout); - } catch (Poco::Net::NetException &exc) { - esyslog("[plex] GetMediaContainer, NetException: %s", exc.displayText().c_str()); - return 0; - } -} - -std::string Plexservice::GetUniversalTranscodeUrl(cVideo* video, int offset, PlexServer* server, bool http) -{ - PlexServer* pSrv = server ? server : video->m_pServer; - Poco::URI transcodeUri(pSrv->GetUri()); - if(!http) { - transcodeUri.setPath("/video/:/transcode/universal/start.m3u8"); - transcodeUri.addQueryParameter("protocol", "hls"); - transcodeUri.addQueryParameter("includeCodecs", "1"); - //transcodeUri.addQueryParameter("copyts", "1"); - transcodeUri.addQueryParameter("directPlay", "0"); - transcodeUri.addQueryParameter("directStream", "1"); - transcodeUri.addQueryParameter("subtitles", "burn"); - transcodeUri.addQueryParameter("audioBoost", "100"); - } else { - transcodeUri.setScheme("http"); // mpv segfaults with https... :-( - transcodeUri.setPath("/video/:/transcode/universal/start"); - transcodeUri.addQueryParameter("protocol", "http"); - - transcodeUri.addQueryParameter("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); - transcodeUri.addQueryParameter("X-Plex-Product", "Chromecast"); - transcodeUri.addQueryParameter("X-Plex-Platform", "Chromecast"); - transcodeUri.addQueryParameter("X-Plex-Token", pSrv->GetAuthToken()); - } - - - // Force set localhost and http - Poco::URI pathUri(pSrv->GetUri()+video->m_sKey); - pathUri.setHost("127.0.0.1"); - pathUri.setScheme("http"); - - transcodeUri.addQueryParameter("path", pathUri.toString()); - transcodeUri.addQueryParameter("mediaIndex", "0"); - transcodeUri.addQueryParameter("partIndex", "0"); - transcodeUri.addQueryParameter("offset", std::to_string(offset) ); - transcodeUri.addQueryParameter("fastSeek", "1"); - - - if(pSrv->IsLocal()) { - transcodeUri.addQueryParameter("videoResolution", "1920x1080"); - transcodeUri.addQueryParameter("maxVideoBitrate", "20000"); - transcodeUri.addQueryParameter("videoQuality", "100"); - } else { - transcodeUri.addQueryParameter("videoResolution", "1280x720"); - transcodeUri.addQueryParameter("maxVideoBitrate", "8000"); - transcodeUri.addQueryParameter("videoQuality", "100"); - } - transcodeUri.addQueryParameter("session", Config::GetInstance().GetUUID()); // TODO: generate Random SessionID - - - if(Config::GetInstance().UseAc3 && !http) { - transcodeUri.addQueryParameter("X-Plex-Client-Profile-Extra", "add-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=ac3)"); - //params << encode("+add-limitation(scope=videoCodec&scopeName=h264&type=lowerBound&name=video.height&value=1080)"); - //params << encode("+add-limitation(scope=videoCodec&scopeName=h264&type=lowerBound&name=video.frameRate&value=25)"); - //params << encode("+add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.frameRate&value=25)"); - } - - return transcodeUri.toString(); -} +namespace plexclient { + + Plexservice::Plexservice(PlexServer *server) { + pServer = server; + } + + Plexservice::Plexservice(PlexServer *server, std::string startUri) { + pServer = server; + StartUri = startUri; + } + + std::string Plexservice::GetMyPlexToken() { + static bool done; + static std::string myToken; + + //todo: cache token in file or db + if (!done) { + std::stringstream ss; + Poco::Base64Encoder b64(ss); + + b64 << Config::GetInstance().GetUsername() << ":" << Config::GetInstance().GetPassword(); + + b64.close(); + std::string tempToken = ss.str(); + + + try { + Poco::Net::HTTPSClientSession plexSession("plex.tv", 443); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/users/sign_in.xml", + Poco::Net::HTTPMessage::HTTP_1_1); + + PlexHelper::AddHttpHeader(request); + request.add("Authorization", Poco::format("Basic %s", tempToken)); + + plexSession.sendRequest(request); + + Poco::Net::HTTPResponse response; + std::istream &rs = plexSession.receiveResponse(response); + if (response.getStatus() == 201) { + // parse the XML Response + user u(&rs); + myToken = u.authenticationToken; + isyslog("[plex] plex.tv login successfull."); + } else { + esyslog("[plex] plex.tv Login failed, check you creditials."); + } + done = true; + plexSession.abort(); + } catch (Poco::Exception &exc) { + esyslog("[plex]Exception in %s s%", __func__, exc.displayText().c_str()); + done = true; + } + + } + return myToken; + } + + void Plexservice::Authenticate() { + if (!Config::GetInstance().UsePlexAccount) return; + try { + std::string token = GetMyPlexToken(); + auto pRequest = CreateRequest("/?X-Plex-Token=" + token); + + Poco::Net::HTTPClientSession session(pServer->GetHost(), pServer->GetPort()); + session.sendRequest(*pRequest); + Poco::Net::HTTPResponse response; + /*std::istream &rs = */ + session.receiveResponse(response); + session.abort(); + // TODO: process response + //Poco::StreamCopier::copyStream(rs, std::cout); + } catch (Poco::Exception &exc) { + esyslog("[plex]Exception in %s s%", __func__, exc.displayText().c_str()); + } + } + + void Plexservice::UpdateResources() { + // We must be autenticated + // https://plex.tv/api/resources?includeHttps=1 + if (!Config::GetInstance().UsePlexAccount) { + isyslog("[plex] To access remote servers, please login with your plex.tv account."); + return; // Plugin is used without plex.tv login + } + isyslog("[plex] Updating remote resources..."); + + + std::shared_ptr<MediaContainer> pContainer = nullptr; + try { + Poco::URI fileuri("https://plex.tv/api/resources?includeHttps=1"); + + Poco::Net::HTTPSClientSession session(fileuri.getHost(), 443); + + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), + Poco::Net::HTTPMessage::HTTP_1_1); + PlexHelper::AddHttpHeader(request); + request.add("X-Plex-Token", GetMyPlexToken()); + + session.sendRequest(request); + Poco::Net::HTTPResponse response; + std::istream &rs = session.receiveResponse(response); + + //Poco::StreamCopier::copyStream(rs, std::cout); + + pContainer = std::shared_ptr<MediaContainer>(new MediaContainer(&rs)); + + } catch (Poco::Net::NetException &exc) { + esyslog("[plex] UpdateResources, NetException: %s", exc.displayText().c_str()); + return; + } catch (Poco::Exception &exc) { + esyslog("[plex] UpdateResources, Exception: %s", exc.displayText().c_str()); + return; + } + + for (std::vector<Device>::iterator d_it = pContainer->m_vDevices.begin(); + d_it != pContainer->m_vDevices.end(); ++d_it) { + + // check device is a server + if (d_it->m_sProvides.find("server") != std::string::npos) { + // is it a remote server? + if (d_it->m_bPublicAddressMatches == false) { + // pick remote connection + for (std::vector<Connection>::iterator c_it = d_it->m_vConnections.begin(); + c_it != d_it->m_vConnections.end(); ++c_it) { + if (c_it->m_bLocal == false) { + dsyslog("[plex] Found server via plex.tv: %s", d_it->m_sName.c_str()); + // a remote Server + plexgdm::GetInstance().AddServer( + PlexServer(c_it->m_sUri, d_it->m_sName, d_it->m_sClientIdentifier, + d_it->m_sAccessToken, d_it->m_bOwned, c_it->m_bLocal)); + } + } + } + } + } + } + + PlexServer *Plexservice::GetServer() { + return pServer; + } + + std::shared_ptr<MediaContainer> Plexservice::GetSection(std::string section, bool putOnStack) { + try { + std::string uri; + if (section[0] == '/') { // Full URI? + uri = section; + } else { + uri = Poco::format("%s/%s", m_vUriStack.top(), section); + } + + if (putOnStack) { + m_vUriStack.push(uri); + } + + dsyslog("[plex] URI: %s%s", pServer->GetUri().c_str(), uri.c_str()); + + bool ok; + auto cSession = pServer->MakeRequest(ok, uri); + Poco::Net::HTTPResponse response; + std::istream &rs = cSession->receiveResponse(response); + if (ok && response.getStatus() == 200) { + std::shared_ptr<MediaContainer> pAllsections(new MediaContainer(&rs, pServer)); + return pAllsections; + } + else { + dsyslog("[plex] URI: %s%s Response bad: s%", pServer->GetUri().c_str(), uri.c_str(), + response.getReasonForStatus(response.getStatus()).c_str()); + return 0; + } + + + } catch (Poco::Net::NetException &exc) { + pServer->Offline = true; + return 0; + } + } + + std::shared_ptr<MediaContainer> Plexservice::GetLastSection(bool current) { + if (m_vUriStack.size() > 1) { + if (!current) { + // discard last one + m_vUriStack.pop(); + } + std::string uri = m_vUriStack.top(); + return GetSection(uri, false); + } + return NULL; + } + + bool Plexservice::IsRoot() { + return m_vUriStack.size() <= 1; + } + + std::unique_ptr<Poco::Net::HTTPRequest> Plexservice::CreateRequest(std::string path) { + std::unique_ptr<Poco::Net::HTTPRequest> pRequest = std::unique_ptr<Poco::Net::HTTPRequest>( + new Poco::Net::HTTPRequest(Poco::Net::HTTPRequest::HTTP_GET, + path, Poco::Net::HTTPMessage::HTTP_1_1)); + + PlexHelper::AddHttpHeader(*pRequest); + + if (Config::GetInstance().UsePlexAccount) { + // Add PlexToken to Header + std::string token = GetMyPlexToken(); + if (pServer && !pServer->GetAuthToken().empty()) { + pRequest->add("X-Plex-Token", pServer->GetAuthToken()); + dsyslog("[plex] Using server access token"); + } else if (!token.empty()) { + pRequest->add("X-Plex-Token", token); + dsyslog("[plex] Using global access token"); + } + } + + return pRequest; + } + + std::shared_ptr<MediaContainer> Plexservice::GetMediaContainer(std::string fullUrl) { + PlexServer *pServer = NULL; + try { + Poco::URI fileuri(fullUrl); + dsyslog("[plex] GetMediaContainer: %s", fullUrl.c_str()); + + pServer = plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()); + + bool ok; + auto cSession = pServer->MakeRequest(ok, fileuri.getPathAndQuery()); + Poco::Net::HTTPResponse response; + std::istream &rs = cSession->receiveResponse(response); + if (ok && response.getStatus() == 200) { + std::shared_ptr<MediaContainer> pAllsections = std::shared_ptr<MediaContainer>( + new MediaContainer(&rs, pServer)); + return pAllsections; + } + return 0; + //Poco::StreamCopier::copyStream(rs, std::cout); + } catch (Poco::Net::NetException &exc) { + esyslog("[plex] GetMediaContainer, NetException: %s", exc.displayText().c_str()); + return 0; + } + } + + std::string Plexservice::GetUniversalTranscodeUrl(cVideo *video, int offset, PlexServer *server, bool http) { + PlexServer *pSrv = server ? server : video->m_pServer; + Poco::URI transcodeUri(pSrv->GetUri()); + if (!http) { + transcodeUri.setPath("/video/:/transcode/universal/start.m3u8"); + transcodeUri.addQueryParameter("protocol", "hls"); + transcodeUri.addQueryParameter("includeCodecs", "1"); + //transcodeUri.addQueryParameter("copyts", "1"); + transcodeUri.addQueryParameter("directPlay", "0"); + transcodeUri.addQueryParameter("directStream", "1"); + transcodeUri.addQueryParameter("subtitles", "burn"); + transcodeUri.addQueryParameter("audioBoost", "100"); + } else { + transcodeUri.setScheme("http"); // mpv segfaults with https... :-( + transcodeUri.setPath("/video/:/transcode/universal/start"); + transcodeUri.addQueryParameter("protocol", "http"); + + transcodeUri.addQueryParameter("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); + transcodeUri.addQueryParameter("X-Plex-Product", "Chromecast"); + transcodeUri.addQueryParameter("X-Plex-Platform", "Chromecast"); + transcodeUri.addQueryParameter("X-Plex-Token", pSrv->GetAuthToken()); + } + + + // Force set localhost and http + Poco::URI pathUri(pSrv->GetUri() + video->m_sKey); + pathUri.setHost("127.0.0.1"); + pathUri.setScheme("http"); + + transcodeUri.addQueryParameter("path", pathUri.toString()); + transcodeUri.addQueryParameter("mediaIndex", "0"); + transcodeUri.addQueryParameter("partIndex", "0"); + transcodeUri.addQueryParameter("offset", std::to_string(offset)); + transcodeUri.addQueryParameter("fastSeek", "1"); + + + if (pSrv->IsLocal()) { + transcodeUri.addQueryParameter("videoResolution", "1920x1080"); + transcodeUri.addQueryParameter("maxVideoBitrate", "20000"); + transcodeUri.addQueryParameter("videoQuality", "100"); + } else { + transcodeUri.addQueryParameter("videoResolution", "1280x720"); + transcodeUri.addQueryParameter("maxVideoBitrate", "8000"); + transcodeUri.addQueryParameter("videoQuality", "100"); + } + transcodeUri.addQueryParameter("session", Config::GetInstance().GetUUID()); // TODO: generate Random SessionID + + + if (Config::GetInstance().UseAc3 && !http) { + transcodeUri.addQueryParameter("X-Plex-Client-Profile-Extra", + "add-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=ac3)"); + //params << encode("+add-limitation(scope=videoCodec&scopeName=h264&type=lowerBound&name=video.height&value=1080)"); + //params << encode("+add-limitation(scope=videoCodec&scopeName=h264&type=lowerBound&name=video.frameRate&value=25)"); + //params << encode("+add-limitation(scope=videoCodec&scopeName=h264&type=upperBound&name=video.frameRate&value=25)"); + } + + return transcodeUri.toString(); + } } diff --git a/Plexservice.h b/Plexservice.h index a40525c..97bf8a2 100644 --- a/Plexservice.h +++ b/Plexservice.h @@ -33,37 +33,45 @@ #include "user.h" #include "MediaContainer.h" -namespace plexclient -{ - -class Plexservice -{ -public: - Plexservice(PlexServer *server); - Plexservice(PlexServer *server, std::string startUri); - - std::shared_ptr<MediaContainer> GetSection(std::string section, bool putOnStack = true); - std::shared_ptr<MediaContainer> GetLastSection(bool current = false); - bool IsRoot(); - PlexServer* GetServer(); - void Authenticate(); - - static std::string GetUniversalTranscodeUrl(cVideo* video, int offset = 0, PlexServer* server = 0, bool http = false); - static std::string GetMyPlexToken(); - static std::shared_ptr<MediaContainer> GetMediaContainer(std::string fullUrl); - //static std::string encode(std::string message); - static void UpdateResources(); - - std::string StartUri; - -private: - Poco::Mutex m_mutex; - PlexServer *pServer; - - std::stack<std::string> m_vUriStack; - std::unique_ptr<Poco::Net::HTTPRequest> CreateRequest(std::string path); - -}; +namespace plexclient { + + class Plexservice { + public: + Plexservice(PlexServer *server); + + Plexservice(PlexServer *server, std::string startUri); + + std::shared_ptr<MediaContainer> GetSection(std::string section, bool putOnStack = true); + + std::shared_ptr<MediaContainer> GetLastSection(bool current = false); + + bool IsRoot(); + + PlexServer *GetServer(); + + void Authenticate(); + + static std::string GetUniversalTranscodeUrl(cVideo *video, int offset = 0, PlexServer *server = 0, + bool http = false); + + static std::string GetMyPlexToken(); + + static std::shared_ptr<MediaContainer> GetMediaContainer(std::string fullUrl); + + //static std::string encode(std::string message); + static void UpdateResources(); + + std::string StartUri; + + private: + Poco::Mutex m_mutex; + PlexServer *pServer; + + std::stack<std::string> m_vUriStack; + + std::unique_ptr<Poco::Net::HTTPRequest> CreateRequest(std::string path); + + }; } @@ -1,36 +1,34 @@ #include "Stream.h" #include <Poco/Format.h> -namespace plexclient -{ +namespace plexclient { -Stream::Stream(Poco::XML::Node* pNode) -{ - if(Poco::icompare(pNode->nodeName(), "Stream") == 0) { + Stream::Stream(Poco::XML::Node *pNode) { + if (Poco::icompare(pNode->nodeName(), "Stream") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pNode->attributes(); - - m_bSelected = GetNodeValueAsBool(pAttribs->getNamedItem("selected")); - m_iID = GetNodeValueAsInt(pAttribs->getNamedItem("id")); - m_iStreamType = GetNodeValueAsInt(pAttribs->getNamedItem("streamType")); - m_iIndex = GetNodeValueAsInt(pAttribs->getNamedItem("index")); - m_iChannels = GetNodeValueAsInt(pAttribs->getNamedItem("channels")); - m_sCodec = GetNodeValue(pAttribs->getNamedItem("codec")); - m_sCodecId = GetNodeValue(pAttribs->getNamedItem("codecID")); - m_sLanguage = GetNodeValue(pAttribs->getNamedItem("language")); - m_sLanguageCode = GetNodeValue(pAttribs->getNamedItem("languageCode")); - m_eStreamType = GetNodeValueAsStreamType(pAttribs->getNamedItem("streamType")); + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pNode->attributes(); - pAttribs->release(); - } -} + m_bSelected = GetNodeValueAsBool(pAttribs->getNamedItem("selected")); + m_iID = GetNodeValueAsInt(pAttribs->getNamedItem("id")); + m_iStreamType = GetNodeValueAsInt(pAttribs->getNamedItem("streamType")); + m_iIndex = GetNodeValueAsInt(pAttribs->getNamedItem("index")); + m_iChannels = GetNodeValueAsInt(pAttribs->getNamedItem("channels")); + m_sCodec = GetNodeValue(pAttribs->getNamedItem("codec")); + m_sCodecId = GetNodeValue(pAttribs->getNamedItem("codecID")); + m_sLanguage = GetNodeValue(pAttribs->getNamedItem("language")); + m_sLanguageCode = GetNodeValue(pAttribs->getNamedItem("languageCode")); + m_eStreamType = GetNodeValueAsStreamType(pAttribs->getNamedItem("streamType")); -std::string Stream::GetSetStreamQuery() -{ - if(m_eStreamType == StreamType::sAUDIO) return Poco::format("audioStreamID=%d", m_iID); - else if(m_eStreamType == StreamType::sSUBTITLE && m_iID >= 0) return Poco::format("subtitleStreamID=%d", m_iID); - else if(m_eStreamType == StreamType::sSUBTITLE && m_iID < 0) return "subtitleStreamID="; - else return ""; -} + pAttribs->release(); + } + } + + std::string Stream::GetSetStreamQuery() { + if (m_eStreamType == StreamType::sAUDIO) return Poco::format("audioStreamID=%d", m_iID); + else if (m_eStreamType == StreamType::sSUBTITLE && m_iID >= 0) + return Poco::format("subtitleStreamID=%d", m_iID); + else if (m_eStreamType == StreamType::sSUBTITLE && m_iID < 0) return "subtitleStreamID="; + else return ""; + } } // namespace @@ -26,29 +26,28 @@ using Poco::XML::Node; using Poco::XML::AutoPtr; using Poco::Exception; -namespace plexclient -{ - -class Stream: XmlObject -{ -public: - Stream(Poco::XML::Node* pNode); - Stream() {}; - -public: - bool m_bSelected; - int m_iID; - int m_iStreamType; - int m_iIndex; - int m_iChannels; - std::string m_sCodec; - std::string m_sCodecId; - std::string m_sLanguage; - std::string m_sLanguageCode; - StreamType m_eStreamType; - - std::string GetSetStreamQuery(); -}; +namespace plexclient { + + class Stream : XmlObject { + public: + Stream(Poco::XML::Node *pNode); + + Stream() { }; + + public: + bool m_bSelected; + int m_iID; + int m_iStreamType; + int m_iIndex; + int m_iChannels; + std::string m_sCodec; + std::string m_sCodecId; + std::string m_sLanguage; + std::string m_sLanguageCode; + StreamType m_eStreamType; + + std::string GetSetStreamQuery(); + }; } diff --git a/SubscriptionManager.cpp b/SubscriptionManager.cpp index 4d90a58..4d4311d 100644 --- a/SubscriptionManager.cpp +++ b/SubscriptionManager.cpp @@ -14,286 +14,269 @@ #include "PlexHelper.h" #include "plex.h" -namespace plexclient -{ - -SubscriptionManager::SubscriptionManager() -{ - m_pStatus = new cSubscriberStatus(); - m_bStoppedSent = true; -} - -void SubscriptionManager::Notify() -{ - //dsyslog("[plex]: '%s'", __FUNCTION__); - Cleanup(); - m_myLock.Lock(&m_myMutex); - for(std::map<std::string, Subscriber>::iterator it = m_mSubcribers.begin() ; it != m_mSubcribers.end(); ++it) { - Subscriber subs = it->second; - subs.SendUpdate(GetMsg(subs.m_iCommandId), false); - } - NotifyServer(); - ReportProgress(); -} - -void SubscriptionManager::ReportProgress() -{ - if(!m_pStatus->pVideo) { - return; - } - - try { - int current, total, speed; - bool play, forward; - if(!m_pStatus->PlayerStopped && m_pStatus->pControl) { - m_pStatus->pControl->GetIndex(current, total); - current = current / m_pStatus->pControl->FramesPerSecond() * 1000; - total = total / m_pStatus->pControl->FramesPerSecond() * 1000; - m_pStatus->pControl->GetReplayMode(play, forward, speed); - } else { - return; - } - - m_pStatus->pControl->GetReplayMode(play, forward, speed); - - std::string state = "playing"; - if (m_pStatus->PlayerStopped) state = "stopped"; - else if(!play) state = "paused"; - - std::map<std::string, std::string> queryMap; - queryMap["key"] = std::to_string(m_pStatus->pVideo->m_iRatingKey); - queryMap["identifier"] = "com.plexapp.plugins.library"; - queryMap["time"] = std::to_string(current); - queryMap["state"] = state; - - bool ok; - auto cSession = m_pStatus->pVideo->m_pServer->MakeRequest(ok, "/:/progress", queryMap); - - } catch (Poco::Exception&) {} -} - -void SubscriptionManager::NotifyServer() -{ - if(m_bStoppedSent && m_pStatus->PlayerStopped) return; - try { - int current, total, speed; - bool play, forward; - cVideo *pVid = NULL; - if(!m_pStatus->PlayerStopped && m_pStatus->pControl) { - m_pStatus->pControl->GetIndex(current, total); - current = current / m_pStatus->pControl->FramesPerSecond() * 1000; - total = total / m_pStatus->pControl->FramesPerSecond() * 1000; - m_pStatus->pControl->GetReplayMode(play, forward, speed); - pVid = m_pStatus->pVideo; - } else { - return; - } - - PlexServer* pServer; - if(pVid) { - pServer = pVid->m_pServer; - } else if ( plexgdm::GetInstance().GetPlexservers().size() > 0) { - pServer = &plexgdm::GetInstance().GetPlexservers().at(0); - } else { - // no plexservers in network - return; - } - - std::map<std::string, std::string> queryMap; - - queryMap["containerKey"] = pVid ? pVid->m_sKey : "/library/metadata/900000"; - queryMap["key"] = pVid ? pVid->m_sKey : "/library/metadata/900000"; - queryMap["ratingKey"] = pVid ? std::to_string(pVid->m_iRatingKey) : "900000"; - - if (m_pStatus->PlayerStopped) queryMap["state"] = "stopped"; - else if(!play) queryMap["state"] = "paused"; - else queryMap["state"] = "playing"; - - queryMap["time"] = std::to_string(current); - queryMap["duration"] = std::to_string(total); - - - Poco::Net::HTTPResponse response; - bool ok; - auto cSession = pServer->MakeRequest(ok, "/:/timeline", queryMap); - - - m_bStoppedSent = m_pStatus->PlayerStopped ? true : false; - } catch (Poco::Exception& e) {} - -} - -void SubscriptionManager::AddSubscriber(Subscriber subs) -{ - m_myLock.Lock(&m_myMutex); - m_mSubcribers[subs.GetUuid()] = subs; -} - -void SubscriptionManager::RemoveSubscriber(std::string uuid) -{ - m_myLock.Lock(&m_myMutex); - if(m_mSubcribers.find(uuid) != m_mSubcribers.end()) { - m_mSubcribers.erase(uuid); - } -} - -void SubscriptionManager::UpdateSubscriber(std::string uuid, std::string commandId) -{ - m_myLock.Lock(&m_myMutex); - if(m_mSubcribers.find(uuid) != m_mSubcribers.end()) { - m_mSubcribers[uuid].m_iCommandId = commandId; - //dsyslog("[plex]: '%s'", __FUNCTION__); - } -} - -std::string SubscriptionManager::GetMsg(std::string commandId) -{ - //dsyslog("[plex]: '%s'", __FUNCTION__); - std::stringstream msg; - msg << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" - "<MediaContainer commandID=\"" << commandId << "\" location=\"navigation\">"; - - msg << "<Timeline location=\"navigation\" state=\"stopped\" time=\"0\" type=\"photo\" />"; - msg << "<Timeline location=\"navigation\" state=\"stopped\" time=\"0\" type=\"music\" />"; - - msg << GetTimelineXml(); - - msg << "</MediaContainer>"; - return msg.str(); -} - -std::string SubscriptionManager::GetTimelineXml() -{ - int current = 0, total = 0, speed; - bool play = false, forward; - cVideo *pVid = NULL; - if(!m_pStatus->PlayerStopped && m_pStatus->pControl) { - m_pStatus->pControl->GetIndex(current, total); - current = current / m_pStatus->pControl->FramesPerSecond() * 1000; - total = total / m_pStatus->pControl->FramesPerSecond() * 1000; - m_pStatus->pControl->GetReplayMode(play, forward, speed); - pVid = m_pStatus->pVideo; - } - - std::stringstream msg; - - msg << "<Timeline location=\"navigation\" state=\""; - if (m_pStatus->PlayerStopped) msg << "stopped"; - else if(!play) msg << "paused"; - else msg << "playing"; - - msg << "\" time=\"" << current << "\" type=\"video\""; - if (!m_pStatus->PlayerStopped) { - msg << " duration=\"" << total << "\""; - msg << " seekRange=\"0-" << total << "\""; - msg << " controllable=\"true\""; - msg << " machineIdentifier=\"" << (pVid ? pVid->m_pServer->GetUuid() : "") << "\""; - msg << " protocol=\"http\""; - msg << " address=\"" << (pVid ? pVid->m_pServer->GetHost() : "") << "\""; - msg << " port=\"" << (pVid ? pVid->m_pServer->GetPort() : 0) << "\""; - msg << " guid=\"" << Config::GetInstance().GetUUID() << "\""; - msg << " containerKey=\"" << (pVid ? pVid->m_sKey : "/library/metadata/900000") << "\""; - msg << " key=\"" << (pVid ? pVid->m_sKey : "/library/metadata/900000") << "\""; - msg << " ratingKey=\"" << (pVid ? pVid->m_iRatingKey : 900000) << "\""; - msg << " volume=\"" << m_pStatus->Volume << "\""; - msg << " shuffle=\"false\""; - } - msg << "/>"; - return msg.str(); -} - -void SubscriptionManager::Cleanup() -{ - m_myLock.Lock(&m_myMutex); - for(std::map<std::string, Subscriber>::iterator it = m_mSubcribers.begin() ; it != m_mSubcribers.end(); ++it) { - Subscriber subs = it->second; - if(subs.m_iAge > 30) { - m_mSubcribers.erase(it); - } - } -} - -Subscriber::Subscriber(std::string protocol, std::string host, int port, std::string uuid, std::string commandId) -{ - m_sProtocol = protocol; - int pos = host.find(":"); - m_sHost = host.substr(0,pos-1); - m_iPort = port; - m_sUuid = uuid; - m_iCommandId = commandId; - m_iAge = 0; -} - -void Subscriber::SendUpdate(std::string msg, bool isNav) -{ - //dsyslog("[plex]: '%s'", __FUNCTION__); - ++m_iAge; - try { - Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_POST, - "/:/timeline", Poco::Net::HTTPMessage::HTTP_1_1); - - PlexHelper::AddHttpHeader(Request); - - Poco::Net::HTTPClientSession session(m_sHost, m_iPort); - - Request.setContentLength(msg.length()); - session.sendRequest(Request) << msg; - - Poco::Net::HTTPResponse response; - session.receiveResponse(response); - - } catch (Poco::Exception& e) {} -} - -ActionManager::ActionManager() {} - -void ActionManager::AddAction(cVideo video) -{ - m_myLock.Lock(&m_myMutex); - m_Action = video; - m_isAction = true; -} - -cVideo ActionManager::GetAction() -{ - m_myLock.Lock(&m_myMutex); - m_isAction = false; - return m_Action; -} - -bool ActionManager::IsAction() -{ - //m_myLock.Lock(&m_myMutex); - return m_isAction; -} - -cSubscriberStatus::cSubscriberStatus() -{ - PlayerStopped = true; - pControl = NULL; -} - -void cSubscriberStatus::Replaying(const cControl* DvbPlayerControl, const char* Name, const char* FileName, bool On) -{ - //dsyslog("[plex]: '%s'", __FUNCTION__); - PlayerStopped = !On; - - if(PlayerStopped) { - cMyPlugin::PlayingFile = false; - } - - pControl = const_cast<cControl*>(DvbPlayerControl); - cHlsPlayerControl* hlsControl = dynamic_cast<cHlsPlayerControl*>(pControl); - if(hlsControl) { - pVideo = &hlsControl->m_Video; - } else if(cMyPlugin::PlayingFile) { - pVideo = &cMyPlugin::CurrentVideo; - } else { - pVideo = NULL; - pControl = NULL; - } - - SubscriptionManager::GetInstance().Notify(); -} +namespace plexclient { + + SubscriptionManager::SubscriptionManager() { + m_pStatus = new cSubscriberStatus(); + m_bStoppedSent = true; + } + + void SubscriptionManager::Notify() { + //dsyslog("[plex]: '%s'", __FUNCTION__); + Cleanup(); + m_myLock.Lock(&m_myMutex); + for (std::map<std::string, Subscriber>::iterator it = m_mSubcribers.begin(); it != m_mSubcribers.end(); ++it) { + Subscriber subs = it->second; + subs.SendUpdate(GetMsg(subs.m_iCommandId), false); + } + NotifyServer(); + ReportProgress(); + } + + void SubscriptionManager::ReportProgress() { + if (!m_pStatus->pVideo) { + return; + } + + try { + int current, total, speed; + bool play, forward; + if (!m_pStatus->PlayerStopped && m_pStatus->pControl) { + m_pStatus->pControl->GetIndex(current, total); + current = current / m_pStatus->pControl->FramesPerSecond() * 1000; + total = total / m_pStatus->pControl->FramesPerSecond() * 1000; + m_pStatus->pControl->GetReplayMode(play, forward, speed); + } else { + return; + } + + m_pStatus->pControl->GetReplayMode(play, forward, speed); + + std::string state = "playing"; + if (m_pStatus->PlayerStopped) state = "stopped"; + else if (!play) state = "paused"; + + std::map<std::string, std::string> queryMap; + queryMap["key"] = std::to_string(m_pStatus->pVideo->m_iRatingKey); + queryMap["identifier"] = "com.plexapp.plugins.library"; + queryMap["time"] = std::to_string(current); + queryMap["state"] = state; + + bool ok; + auto cSession = m_pStatus->pVideo->m_pServer->MakeRequest(ok, "/:/progress", queryMap); + + } catch (Poco::Exception &) { } + } + + void SubscriptionManager::NotifyServer() { + if (m_bStoppedSent && m_pStatus->PlayerStopped) return; + try { + int current, total, speed; + bool play, forward; + cVideo *pVid = NULL; + if (!m_pStatus->PlayerStopped && m_pStatus->pControl) { + m_pStatus->pControl->GetIndex(current, total); + current = current / m_pStatus->pControl->FramesPerSecond() * 1000; + total = total / m_pStatus->pControl->FramesPerSecond() * 1000; + m_pStatus->pControl->GetReplayMode(play, forward, speed); + pVid = m_pStatus->pVideo; + } else { + return; + } + + PlexServer *pServer; + if (pVid) { + pServer = pVid->m_pServer; + } else if (plexgdm::GetInstance().GetPlexservers().size() > 0) { + pServer = &plexgdm::GetInstance().GetPlexservers().at(0); + } else { + // no plexservers in network + return; + } + + std::map<std::string, std::string> queryMap; + + queryMap["containerKey"] = pVid ? pVid->m_sKey : "/library/metadata/900000"; + queryMap["key"] = pVid ? pVid->m_sKey : "/library/metadata/900000"; + queryMap["ratingKey"] = pVid ? std::to_string(pVid->m_iRatingKey) : "900000"; + + if (m_pStatus->PlayerStopped) queryMap["state"] = "stopped"; + else if (!play) queryMap["state"] = "paused"; + else queryMap["state"] = "playing"; + + queryMap["time"] = std::to_string(current); + queryMap["duration"] = std::to_string(total); + + + Poco::Net::HTTPResponse response; + bool ok; + auto cSession = pServer->MakeRequest(ok, "/:/timeline", queryMap); + + + m_bStoppedSent = m_pStatus->PlayerStopped ? true : false; + } catch (Poco::Exception &e) { } + + } + + void SubscriptionManager::AddSubscriber(Subscriber subs) { + m_myLock.Lock(&m_myMutex); + m_mSubcribers[subs.GetUuid()] = subs; + } + + void SubscriptionManager::RemoveSubscriber(std::string uuid) { + m_myLock.Lock(&m_myMutex); + if (m_mSubcribers.find(uuid) != m_mSubcribers.end()) { + m_mSubcribers.erase(uuid); + } + } + + void SubscriptionManager::UpdateSubscriber(std::string uuid, std::string commandId) { + m_myLock.Lock(&m_myMutex); + if (m_mSubcribers.find(uuid) != m_mSubcribers.end()) { + m_mSubcribers[uuid].m_iCommandId = commandId; + //dsyslog("[plex]: '%s'", __FUNCTION__); + } + } + + std::string SubscriptionManager::GetMsg(std::string commandId) { + //dsyslog("[plex]: '%s'", __FUNCTION__); + std::stringstream msg; + msg << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<MediaContainer commandID=\"" << commandId << "\" location=\"navigation\">"; + + msg << "<Timeline location=\"navigation\" state=\"stopped\" time=\"0\" type=\"photo\" />"; + msg << "<Timeline location=\"navigation\" state=\"stopped\" time=\"0\" type=\"music\" />"; + + msg << GetTimelineXml(); + + msg << "</MediaContainer>"; + return msg.str(); + } + + std::string SubscriptionManager::GetTimelineXml() { + int current = 0, total = 0, speed; + bool play = false, forward; + cVideo *pVid = NULL; + if (!m_pStatus->PlayerStopped && m_pStatus->pControl) { + m_pStatus->pControl->GetIndex(current, total); + current = current / m_pStatus->pControl->FramesPerSecond() * 1000; + total = total / m_pStatus->pControl->FramesPerSecond() * 1000; + m_pStatus->pControl->GetReplayMode(play, forward, speed); + pVid = m_pStatus->pVideo; + } + + std::stringstream msg; + + msg << "<Timeline location=\"navigation\" state=\""; + if (m_pStatus->PlayerStopped) msg << "stopped"; + else if (!play) msg << "paused"; + else msg << "playing"; + + msg << "\" time=\"" << current << "\" type=\"video\""; + if (!m_pStatus->PlayerStopped) { + msg << " duration=\"" << total << "\""; + msg << " seekRange=\"0-" << total << "\""; + msg << " controllable=\"true\""; + msg << " machineIdentifier=\"" << (pVid ? pVid->m_pServer->GetUuid() : "") << "\""; + msg << " protocol=\"http\""; + msg << " address=\"" << (pVid ? pVid->m_pServer->GetHost() : "") << "\""; + msg << " port=\"" << (pVid ? pVid->m_pServer->GetPort() : 0) << "\""; + msg << " guid=\"" << Config::GetInstance().GetUUID() << "\""; + msg << " containerKey=\"" << (pVid ? pVid->m_sKey : "/library/metadata/900000") << "\""; + msg << " key=\"" << (pVid ? pVid->m_sKey : "/library/metadata/900000") << "\""; + msg << " ratingKey=\"" << (pVid ? pVid->m_iRatingKey : 900000) << "\""; + msg << " volume=\"" << m_pStatus->Volume << "\""; + msg << " shuffle=\"false\""; + } + msg << "/>"; + return msg.str(); + } + + void SubscriptionManager::Cleanup() { + m_myLock.Lock(&m_myMutex); + for (std::map<std::string, Subscriber>::iterator it = m_mSubcribers.begin(); it != m_mSubcribers.end(); ++it) { + Subscriber subs = it->second; + if (subs.m_iAge > 30) { + m_mSubcribers.erase(it); + } + } + } + + Subscriber::Subscriber(std::string protocol, std::string host, int port, std::string uuid, std::string commandId) { + m_sProtocol = protocol; + int pos = host.find(":"); + m_sHost = host.substr(0, pos - 1); + m_iPort = port; + m_sUuid = uuid; + m_iCommandId = commandId; + m_iAge = 0; + } + + void Subscriber::SendUpdate(std::string msg, bool isNav) { + //dsyslog("[plex]: '%s'", __FUNCTION__); + ++m_iAge; + try { + Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_POST, + "/:/timeline", Poco::Net::HTTPMessage::HTTP_1_1); + + PlexHelper::AddHttpHeader(Request); + + Poco::Net::HTTPClientSession session(m_sHost, m_iPort); + + Request.setContentLength(msg.length()); + session.sendRequest(Request) << msg; + + Poco::Net::HTTPResponse response; + session.receiveResponse(response); + + } catch (Poco::Exception &e) { } + } + + ActionManager::ActionManager() { } + + void ActionManager::AddAction(cVideo video) { + m_myLock.Lock(&m_myMutex); + m_Action = video; + m_isAction = true; + } + + cVideo ActionManager::GetAction() { + m_myLock.Lock(&m_myMutex); + m_isAction = false; + return m_Action; + } + + bool ActionManager::IsAction() { + //m_myLock.Lock(&m_myMutex); + return m_isAction; + } + + cSubscriberStatus::cSubscriberStatus() { + PlayerStopped = true; + pControl = NULL; + } + + void cSubscriberStatus::Replaying(const cControl *DvbPlayerControl, const char *Name, const char *FileName, + bool On) { + //dsyslog("[plex]: '%s'", __FUNCTION__); + PlayerStopped = !On; + + if (PlayerStopped) { + cMyPlugin::PlayingFile = false; + } + + pControl = const_cast<cControl *>(DvbPlayerControl); + cHlsPlayerControl *hlsControl = dynamic_cast<cHlsPlayerControl *>(pControl); + if (hlsControl) { + pVideo = &hlsControl->m_Video; + } else if (cMyPlugin::PlayingFile) { + pVideo = &cMyPlugin::CurrentVideo; + } else { + pVideo = NULL; + pControl = NULL; + } + + SubscriptionManager::GetInstance().Notify(); + } } // Namespace diff --git a/SubscriptionManager.h b/SubscriptionManager.h index 55facef..fb86e75 100644 --- a/SubscriptionManager.h +++ b/SubscriptionManager.h @@ -11,97 +11,111 @@ #include "hlsPlayerControl.h" #include "PVideo.h" -namespace plexclient -{ - -class cSubscriberStatus : public cStatus -{ -protected: - virtual void Replaying(const cControl *DvbPlayerControl, const char *Name, const char *FileName, bool On); - -public: - cSubscriberStatus(); - bool PlayerPaused; - bool PlayerStopped; - cControl* pControl; - cVideo* pVideo; - int Volume; - -}; - -class Subscriber -{ - friend class SubscriptionManager; -public: - std::string m_iCommandId; - Subscriber() {}; - Subscriber(std::string protocol, std::string host, int port, std::string uuid, std::string commandId); - - std::string GetUuid() { - return m_sUuid; - } - - void SendUpdate(std::string msg, bool isNav); - - virtual std::string to_string() { - return "Subscriber-> Host: " + m_sHost + "; Port: " + std::string(itoa(m_iPort)) + "; Uuid:" + m_sUuid + "; CmdID:" + m_iCommandId; - } - -private: - std::string m_sProtocol; - std::string m_sHost; - int m_iPort; - std::string m_sUuid; - - int m_iAge; -}; - - -class SubscriptionManager -{ -public: - static SubscriptionManager& GetInstance() { - static SubscriptionManager instance; - return instance; - } - void AddSubscriber(Subscriber subs); - void RemoveSubscriber(std::string uuid); - void UpdateSubscriber(std::string uuid, std::string commandId); - std::string GetMsg(std::string commandId); - void Notify(); - -private: - SubscriptionManager(); - cMutexLock m_myLock; - cMutex m_myMutex; - std::map<std::string, Subscriber> m_mSubcribers; - cSubscriberStatus* m_pStatus; - bool m_bStoppedSent; - - void ReportProgress(); - void NotifyServer(); - void Cleanup(); - std::string GetTimelineXml(); -}; - -class ActionManager -{ -public: - static ActionManager& GetInstance() { - static ActionManager instance; - return instance; - } - void AddAction(cVideo video); - cVideo GetAction(); - bool IsAction(); - -private: - cMutexLock m_myLock; - cMutex m_myMutex; - ActionManager(); - cVideo m_Action; - bool m_isAction; -}; +namespace plexclient { + + class cSubscriberStatus : public cStatus { + protected: + virtual void Replaying(const cControl *DvbPlayerControl, const char *Name, const char *FileName, bool On); + + public: + cSubscriberStatus(); + + bool PlayerPaused; + bool PlayerStopped; + cControl *pControl; + cVideo *pVideo; + int Volume; + + }; + + class Subscriber { + friend class SubscriptionManager; + + public: + std::string m_iCommandId; + + Subscriber() { }; + + Subscriber(std::string protocol, std::string host, int port, std::string uuid, std::string commandId); + + std::string GetUuid() { + return m_sUuid; + } + + void SendUpdate(std::string msg, bool isNav); + + virtual std::string to_string() { + return "Subscriber-> Host: " + m_sHost + "; Port: " + std::string(itoa(m_iPort)) + "; Uuid:" + m_sUuid + + "; CmdID:" + m_iCommandId; + } + + private: + std::string m_sProtocol; + std::string m_sHost; + int m_iPort; + std::string m_sUuid; + + int m_iAge; + }; + + + class SubscriptionManager { + public: + static SubscriptionManager &GetInstance() { + static SubscriptionManager instance; + return instance; + } + + void AddSubscriber(Subscriber subs); + + void RemoveSubscriber(std::string uuid); + + void UpdateSubscriber(std::string uuid, std::string commandId); + + std::string GetMsg(std::string commandId); + + void Notify(); + + private: + SubscriptionManager(); + + cMutexLock m_myLock; + cMutex m_myMutex; + std::map<std::string, Subscriber> m_mSubcribers; + cSubscriberStatus *m_pStatus; + bool m_bStoppedSent; + + void ReportProgress(); + + void NotifyServer(); + + void Cleanup(); + + std::string GetTimelineXml(); + }; + + class ActionManager { + public: + static ActionManager &GetInstance() { + static ActionManager instance; + return instance; + } + + void AddAction(cVideo video); + + cVideo GetAction(); + + bool IsAction(); + + private: + cMutexLock m_myLock; + cMutex m_myMutex; + + ActionManager(); + + cVideo m_Action; + bool m_isAction; + }; } diff --git a/XmlObject.cpp b/XmlObject.cpp index 8c01dd7..c13cbed 100644 --- a/XmlObject.cpp +++ b/XmlObject.cpp @@ -1,170 +1,158 @@ #include "XmlObject.h" #include <vdr/tools.h> -namespace plexclient -{ -std::string XmlObject::GetNodeValue(Poco::XML::Node* pNode) -{ - std::string value; - if(pNode != 0) { - value = pNode->getNodeValue(); - } - return value; -} - -int XmlObject::GetNodeValueAsInt(Poco::XML::Node* pNode) -{ - int value = -1; - if(pNode != 0) { - try { - value = atoi(pNode->getNodeValue().c_str()); - } catch(Poco::Exception) {} - } - return value; -} - -long XmlObject::GetNodeValueAsLong(Poco::XML::Node* pNode) -{ - long value = -1; - if(pNode != 0) { - try { - value = atol(pNode->getNodeValue().c_str()); - } catch(Poco::Exception) {} - } - return value; -} - -double XmlObject::GetNodeValueAsDouble(Poco::XML::Node* pNode) -{ - double value = -1; - if(pNode != 0) { - try { - value = atod(pNode->getNodeValue().c_str()); - } catch(Poco::Exception) {} - } - return value; -} - -bool XmlObject::GetNodeValueAsBool(Poco::XML::Node* pNode) -{ - bool value = false; - if(pNode != 0) { - value = pNode->getNodeValue() == "1"; - } - return value; -} - -Poco::Timestamp XmlObject::GetNodeValueAsTimeStamp(Poco::XML::Node* pNode) -{ - Poco::Timestamp value; - if(pNode != 0) { - try { - long lValue = atol(pNode->nodeValue().c_str()); - value = Poco::Timestamp(lValue); - } catch (Poco::Exception) {} - } - return value; -} - -Poco::DateTime XmlObject::GetNodeValueAsDateTime(Poco::XML::Node* pNode) -{ - Poco::DateTime value; - if(pNode != 0) { - try { - std::string format = "%Y-%m-%d"; - std::string val = pNode->nodeValue(); - int diff; - value = Poco::DateTimeParser::parse(format, val, diff); - } catch (Poco::Exception) {} - } - return value; -} - -MediaType XmlObject::GetNodeValueAsMediaType(Poco::XML::Node* pNode) -{ - MediaType type = MediaType::UNDEF; - - if(pNode != 0) { - std::string sType = pNode->nodeValue(); - if (Poco::icompare(sType, "photo") == 0) { - type = MediaType::PHOTO; - } else if (Poco::icompare(sType, "movie") == 0) { - type = MediaType::MOVIE; - } else if (Poco::icompare(sType, "music") == 0) { - type = MediaType::MUSIC; - } else if (Poco::icompare(sType, "show") == 0) { - type = MediaType::SHOW; - } else if (Poco::icompare(sType, "season") == 0) { - type = MediaType::SEASON; - } else if (Poco::icompare(sType, "episode") == 0) { - type = MediaType::EPISODE; - } else if (Poco::icompare(sType, "clip") == 0) { - type = MediaType::CLIP; - } - } - return type; -} - -StreamType XmlObject::GetNodeValueAsStreamType(Poco::XML::Node* pNode) -{ - StreamType type = StreamType::sUNDEF; - - if(pNode != 0) { - int iType = GetNodeValueAsInt(pNode); - switch(iType) { - case 1: - type = StreamType::sVIDEO; - break; - case 2: - type = StreamType::sAUDIO; - break; - case 3: - type = StreamType::sSUBTITLE; - break; - default: - type = StreamType::sUNDEF; - break; - } - } - return type; -} - -PlaylistType XmlObject::GetNodeValueAsPlaylistType(Poco::XML::Node* pNode) -{ - PlaylistType type = PlaylistType::Undef; - - if(pNode != 0) { - std::string sType = pNode->nodeValue(); - if (Poco::icompare(sType, "photo") == 0) { - type = PlaylistType::Photo; - } else if (Poco::icompare(sType, "video") == 0) { - type = PlaylistType::Video; - } else if (Poco::icompare(sType, "audio") == 0) { - type = PlaylistType::Audio; - } - } - return type; -} - -ExtraType XmlObject::GetNodeValueAsExtraType(Poco::XML::Node* pNode) -{ - ExtraType type = ExtraType::Unkown; - - if(pNode != 0) { - int iType = GetNodeValueAsInt(pNode); - switch(iType) { - case 1: - type = ExtraType::Trailer; - break; - case 5: - type = ExtraType::BehindTheScenes; - break; - default: - type = ExtraType::Unkown; - break; - } - } - return type; -} +namespace plexclient { + std::string XmlObject::GetNodeValue(Poco::XML::Node *pNode) { + std::string value; + if (pNode != 0) { + value = pNode->getNodeValue(); + } + return value; + } + + int XmlObject::GetNodeValueAsInt(Poco::XML::Node *pNode) { + int value = -1; + if (pNode != 0) { + try { + value = atoi(pNode->getNodeValue().c_str()); + } catch (Poco::Exception) { } + } + return value; + } + + long XmlObject::GetNodeValueAsLong(Poco::XML::Node *pNode) { + long value = -1; + if (pNode != 0) { + try { + value = atol(pNode->getNodeValue().c_str()); + } catch (Poco::Exception) { } + } + return value; + } + + double XmlObject::GetNodeValueAsDouble(Poco::XML::Node *pNode) { + double value = -1; + if (pNode != 0) { + try { + value = atod(pNode->getNodeValue().c_str()); + } catch (Poco::Exception) { } + } + return value; + } + + bool XmlObject::GetNodeValueAsBool(Poco::XML::Node *pNode) { + bool value = false; + if (pNode != 0) { + value = pNode->getNodeValue() == "1"; + } + return value; + } + + Poco::Timestamp XmlObject::GetNodeValueAsTimeStamp(Poco::XML::Node *pNode) { + Poco::Timestamp value; + if (pNode != 0) { + try { + long lValue = atol(pNode->nodeValue().c_str()); + value = Poco::Timestamp(lValue); + } catch (Poco::Exception) { } + } + return value; + } + + Poco::DateTime XmlObject::GetNodeValueAsDateTime(Poco::XML::Node *pNode) { + Poco::DateTime value; + if (pNode != 0) { + try { + std::string format = "%Y-%m-%d"; + std::string val = pNode->nodeValue(); + int diff; + value = Poco::DateTimeParser::parse(format, val, diff); + } catch (Poco::Exception) { } + } + return value; + } + + MediaType XmlObject::GetNodeValueAsMediaType(Poco::XML::Node *pNode) { + MediaType type = MediaType::UNDEF; + + if (pNode != 0) { + std::string sType = pNode->nodeValue(); + if (Poco::icompare(sType, "photo") == 0) { + type = MediaType::PHOTO; + } else if (Poco::icompare(sType, "movie") == 0) { + type = MediaType::MOVIE; + } else if (Poco::icompare(sType, "music") == 0) { + type = MediaType::MUSIC; + } else if (Poco::icompare(sType, "show") == 0) { + type = MediaType::SHOW; + } else if (Poco::icompare(sType, "season") == 0) { + type = MediaType::SEASON; + } else if (Poco::icompare(sType, "episode") == 0) { + type = MediaType::EPISODE; + } else if (Poco::icompare(sType, "clip") == 0) { + type = MediaType::CLIP; + } + } + return type; + } + + StreamType XmlObject::GetNodeValueAsStreamType(Poco::XML::Node *pNode) { + StreamType type = StreamType::sUNDEF; + + if (pNode != 0) { + int iType = GetNodeValueAsInt(pNode); + switch (iType) { + case 1: + type = StreamType::sVIDEO; + break; + case 2: + type = StreamType::sAUDIO; + break; + case 3: + type = StreamType::sSUBTITLE; + break; + default: + type = StreamType::sUNDEF; + break; + } + } + return type; + } + + PlaylistType XmlObject::GetNodeValueAsPlaylistType(Poco::XML::Node *pNode) { + PlaylistType type = PlaylistType::Undef; + + if (pNode != 0) { + std::string sType = pNode->nodeValue(); + if (Poco::icompare(sType, "photo") == 0) { + type = PlaylistType::Photo; + } else if (Poco::icompare(sType, "video") == 0) { + type = PlaylistType::Video; + } else if (Poco::icompare(sType, "audio") == 0) { + type = PlaylistType::Audio; + } + } + return type; + } + + ExtraType XmlObject::GetNodeValueAsExtraType(Poco::XML::Node *pNode) { + ExtraType type = ExtraType::Unkown; + + if (pNode != 0) { + int iType = GetNodeValueAsInt(pNode); + switch (iType) { + case 1: + type = ExtraType::Trailer; + break; + case 5: + type = ExtraType::BehindTheScenes; + break; + default: + type = ExtraType::Unkown; + break; + } + } + return type; + } } diff --git a/XmlObject.h b/XmlObject.h index 4c64a6c..942e061 100644 --- a/XmlObject.h +++ b/XmlObject.h @@ -10,31 +10,47 @@ #include <Poco/String.h> #include <Poco/Exception.h> -namespace plexclient -{ - -enum class MediaType {UNDEF = 0, MOVIE, SHOW, SEASON, EPISODE, MUSIC, PHOTO, CLIP, PLAYLIST}; -enum class PlaylistType { Undef, Video, Audio, Photo }; -enum class StreamType {sUNDEF = 0, sVIDEO = 1, sAUDIO = 2, sSUBTITLE = 3}; -enum class ExtraType { Unkown = 0, Trailer = 1, BehindTheScenes = 5 }; - -class XmlObject -{ -protected: - static std::string GetNodeValue(Poco::XML::Node* pNode); - static int GetNodeValueAsInt(Poco::XML::Node* pNode); - static long GetNodeValueAsLong(Poco::XML::Node* pNode); - static double GetNodeValueAsDouble(Poco::XML::Node* pNode); - static bool GetNodeValueAsBool(Poco::XML::Node* pNode); - static Poco::Timestamp GetNodeValueAsTimeStamp(Poco::XML::Node* pNode); - static Poco::DateTime GetNodeValueAsDateTime(Poco::XML::Node* pNode); - static MediaType GetNodeValueAsMediaType(Poco::XML::Node* pNode); - static StreamType GetNodeValueAsStreamType(Poco::XML::Node* pNode); - static PlaylistType GetNodeValueAsPlaylistType(Poco::XML::Node* pNode); - static ExtraType GetNodeValueAsExtraType(Poco::XML::Node* pNode); - -private: -}; +namespace plexclient { + + enum class MediaType { + UNDEF = 0, MOVIE, SHOW, SEASON, EPISODE, MUSIC, PHOTO, CLIP, PLAYLIST + }; + enum class PlaylistType { + Undef, Video, Audio, Photo + }; + enum class StreamType { + sUNDEF = 0, sVIDEO = 1, sAUDIO = 2, sSUBTITLE = 3 + }; + enum class ExtraType { + Unkown = 0, Trailer = 1, BehindTheScenes = 5 + }; + + class XmlObject { + protected: + static std::string GetNodeValue(Poco::XML::Node *pNode); + + static int GetNodeValueAsInt(Poco::XML::Node *pNode); + + static long GetNodeValueAsLong(Poco::XML::Node *pNode); + + static double GetNodeValueAsDouble(Poco::XML::Node *pNode); + + static bool GetNodeValueAsBool(Poco::XML::Node *pNode); + + static Poco::Timestamp GetNodeValueAsTimeStamp(Poco::XML::Node *pNode); + + static Poco::DateTime GetNodeValueAsDateTime(Poco::XML::Node *pNode); + + static MediaType GetNodeValueAsMediaType(Poco::XML::Node *pNode); + + static StreamType GetNodeValueAsStreamType(Poco::XML::Node *pNode); + + static PlaylistType GetNodeValueAsPlaylistType(Poco::XML::Node *pNode); + + static ExtraType GetNodeValueAsExtraType(Poco::XML::Node *pNode); + + private: + }; } diff --git a/browserGrid.cpp b/browserGrid.cpp index 4fcbb2f..8cebb83 100644 --- a/browserGrid.cpp +++ b/browserGrid.cpp @@ -7,320 +7,315 @@ #include "pictureCache.h" #include "tokendefinitions.h" -cBrowserGrid::cBrowserGrid(std::shared_ptr<skindesignerapi::cOsdView> rootView) : cViewGridNavigator(rootView) -{ - m_pBackground = std::shared_ptr<skindesignerapi::cViewElement>(rootView->GetViewElement((int)eViewElementsRoot::background)); - m_pHeader = std::shared_ptr<skindesignerapi::cViewElement>(rootView->GetViewElement((int)eViewElementsRoot::header)); - m_pfooter = std::shared_ptr<skindesignerapi::cViewElement>(rootView->GetViewElement((int)eViewElementsRoot::footer)); - m_pInfopane = std::shared_ptr<skindesignerapi::cViewElement>(rootView->GetViewElement((int)eViewElementsRoot::infopane)); - m_pWatch = std::shared_ptr<skindesignerapi::cViewElement>(rootView->GetViewElement((int)eViewElementsRoot::watch)); - m_pScrollbar = std::shared_ptr<skindesignerapi::cViewElement>(rootView->GetViewElement((int)eViewElementsRoot::scrollbar)); - m_lastsecond = 0; - - m_pService = NULL; - m_pContainer = NULL; - m_viewEntryIndex = 0; - m_redrawBackground = true; - - Config *conf = &Config::GetInstance(); - if(conf->DefaultViewMode == ViewMode::Cover) { - SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(rootView->GetViewGrid((int)eViewGrids::cover) )); - SetGridDimensions(conf->CoverGridRows, conf->CoverGridColumns); - } else if(conf->DefaultViewMode == ViewMode::Detail) { - SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(rootView->GetViewGrid((int)eViewGrids::detail) )); - SetGridDimensions(conf->DetailGridRows, conf->DetailGridColumns); - } else if(conf->DefaultViewMode == ViewMode::List) { - SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(rootView->GetViewGrid((int)eViewGrids::list) )); - SetGridDimensions(conf->ListGridRows, conf->ListGridColumns); - } - - SwitchGrid(m_viewEntryIndex); - SwitchView(); +cBrowserGrid::cBrowserGrid(std::shared_ptr<skindesignerapi::cOsdView> rootView) : cViewGridNavigator(rootView) { + m_pBackground = std::shared_ptr<skindesignerapi::cViewElement>( + rootView->GetViewElement((int) eViewElementsRoot::background)); + m_pHeader = std::shared_ptr<skindesignerapi::cViewElement>( + rootView->GetViewElement((int) eViewElementsRoot::header)); + m_pfooter = std::shared_ptr<skindesignerapi::cViewElement>( + rootView->GetViewElement((int) eViewElementsRoot::footer)); + m_pInfopane = std::shared_ptr<skindesignerapi::cViewElement>( + rootView->GetViewElement((int) eViewElementsRoot::infopane)); + m_pWatch = std::shared_ptr<skindesignerapi::cViewElement>(rootView->GetViewElement((int) eViewElementsRoot::watch)); + m_pScrollbar = std::shared_ptr<skindesignerapi::cViewElement>( + rootView->GetViewElement((int) eViewElementsRoot::scrollbar)); + m_lastsecond = 0; + + m_pService = NULL; + m_pContainer = NULL; + m_viewEntryIndex = 0; + m_redrawBackground = true; + + Config *conf = &Config::GetInstance(); + if (conf->DefaultViewMode == ViewMode::Cover) { + SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(rootView->GetViewGrid((int) eViewGrids::cover))); + SetGridDimensions(conf->CoverGridRows, conf->CoverGridColumns); + } else if (conf->DefaultViewMode == ViewMode::Detail) { + SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(rootView->GetViewGrid((int) eViewGrids::detail))); + SetGridDimensions(conf->DetailGridRows, conf->DetailGridColumns); + } else if (conf->DefaultViewMode == ViewMode::List) { + SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(rootView->GetViewGrid((int) eViewGrids::list))); + SetGridDimensions(conf->ListGridRows, conf->ListGridColumns); + } + + SwitchGrid(m_viewEntryIndex); + SwitchView(); } -cBrowserGrid::~cBrowserGrid() -{ - m_vServerElements.clear(); - m_vElements.clear(); +cBrowserGrid::~cBrowserGrid() { + m_vServerElements.clear(); + m_vElements.clear(); } -void cBrowserGrid::Clear() -{ - m_pBackground->Clear(); - m_pfooter->Clear(); - m_pInfopane->Clear(); - m_pWatch->Clear(); - m_pGrid->Clear(); +void cBrowserGrid::Clear() { + m_pBackground->Clear(); + m_pfooter->Clear(); + m_pInfopane->Clear(); + m_pWatch->Clear(); + m_pGrid->Clear(); } -void cBrowserGrid::Flush() -{ - if(m_redrawBackground){ - m_pBackground->Display(); - m_redrawBackground = false; - } - - cMutexLock MutexLock(&cPlexSdOsd::RedrawMutex); - m_pGrid->Display(); - m_pScrollbar->Display(); - - m_pRootView->Display(); +void cBrowserGrid::Flush() { + if (m_redrawBackground) { + m_pBackground->Display(); + m_redrawBackground = false; + } + + cMutexLock MutexLock(&cPlexSdOsd::RedrawMutex); + m_pGrid->Display(); + m_pScrollbar->Display(); + + m_pRootView->Display(); } -void cBrowserGrid::SwitchView(ViewMode mode) -{ - auto selObj = SelectedObject(); - if(!selObj) return; - - Config *conf = &Config::GetInstance(); - conf->DefaultViewMode = mode; - if(conf->DefaultViewMode == ViewMode::Cover) { - SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(m_pRootView->GetViewGrid((int)eViewGrids::cover) )); - SetGridDimensions(conf->CoverGridRows, conf->CoverGridColumns); - } else if(conf->DefaultViewMode == ViewMode::Detail) { - SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(m_pRootView->GetViewGrid((int)eViewGrids::detail) )); - SetGridDimensions(conf->DetailGridRows, conf->DetailGridColumns); - } else if(conf->DefaultViewMode == ViewMode::List) { - SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(m_pRootView->GetViewGrid((int)eViewGrids::list) )); - SetGridDimensions(conf->ListGridRows, conf->ListGridColumns); - } - - int activePos = selObj->AbsolutePosition; - //ProcessData(); - - for(std::vector<cGridElement*>::iterator it = m_vElements.begin(); it != m_vElements.end(); ++it) { - cGridElement *elem = *it; - elem->Position = -1; - elem->Dirty(); - elem->SetPosition(-1,-1); - } - - m_pGrid->Clear(); - m_startIndex = activePos; - m_setIterator = true; - FilterElements(0); +void cBrowserGrid::SwitchView(ViewMode mode) { + auto selObj = SelectedObject(); + if (!selObj) return; + + Config *conf = &Config::GetInstance(); + conf->DefaultViewMode = mode; + if (conf->DefaultViewMode == ViewMode::Cover) { + SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(m_pRootView->GetViewGrid((int) eViewGrids::cover))); + SetGridDimensions(conf->CoverGridRows, conf->CoverGridColumns); + } else if (conf->DefaultViewMode == ViewMode::Detail) { + SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(m_pRootView->GetViewGrid((int) eViewGrids::detail))); + SetGridDimensions(conf->DetailGridRows, conf->DetailGridColumns); + } else if (conf->DefaultViewMode == ViewMode::List) { + SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(m_pRootView->GetViewGrid((int) eViewGrids::list))); + SetGridDimensions(conf->ListGridRows, conf->ListGridColumns); + } + + int activePos = selObj->AbsolutePosition; + //ProcessData(); + + for (std::vector<cGridElement *>::iterator it = m_vElements.begin(); it != m_vElements.end(); ++it) { + cGridElement *elem = *it; + elem->Position = -1; + elem->Dirty(); + elem->SetPosition(-1, -1); + } + + m_pGrid->Clear(); + m_startIndex = activePos; + m_setIterator = true; + FilterElements(0); } -void cBrowserGrid::NextViewMode() -{ - ViewMode mode = Config::GetInstance().DefaultViewMode; - if(mode == ViewMode::Cover) { - mode = ViewMode::Detail; - } else if(mode == ViewMode::Detail) { - mode = ViewMode::List; - } else if(mode == ViewMode::List) { - mode = ViewMode::Cover; - } - SwitchView(mode); +void cBrowserGrid::NextViewMode() { + ViewMode mode = Config::GetInstance().DefaultViewMode; + if (mode == ViewMode::Cover) { + mode = ViewMode::Detail; + } else if (mode == ViewMode::Detail) { + mode = ViewMode::List; + } else if (mode == ViewMode::List) { + mode = ViewMode::Cover; + } + SwitchView(mode); } -void cBrowserGrid::SwitchGrid(int index) -{ - m_pHeader->Clear(); - m_pHeader->ClearTokens(); - m_pHeader->AddIntToken((int)eTokenGridInt::columns, m_columns); - m_pHeader->AddIntToken((int)eTokenGridInt::rows, m_rows); - m_pHeader->AddIntToken((int)eTokenGridInt::totalcount, m_vElements.size()); - - if(plexclient::plexgdm::GetInstance().GetFirstServer()) { - if(m_viewEntryIndex < (int)Config::GetInstance().m_viewentries.size()) { - ViewEntry entry = Config::GetInstance().m_viewentries[index]; - m_pHeader->AddStringToken((int)eTokenGridStr::tabname, tr(entry.Name.c_str())); - m_pService = std::shared_ptr<plexclient::Plexservice>(new plexclient::Plexservice( plexclient::plexgdm::GetInstance().GetFirstServer(), entry.PlexPath ) ); - m_pContainer = m_pService->GetSection(m_pService->StartUri); - m_bServersAreRoot = false; - m_vServerElements.clear(); - } else { - //Server View - m_pHeader->AddStringToken((int)eTokenGridStr::tabname, tr("Library")); - m_pService = NULL; - m_pContainer = NULL; - m_bServersAreRoot = true; - SetServerElements(); - } - } else { - m_pHeader->AddStringToken((int)eTokenGridStr::tabname, tr("No Plex Media Server found.")); - m_pInfopane->AddStringToken((int)eTokenGridStr::title, tr("No Plex Media Server found.")); - m_pService = NULL; - m_pContainer = NULL; - } - ProcessData(); - auto selObj = SelectedObject(); - if(selObj) { - selObj->AddTokens(m_pHeader, false); - m_pHeader->AddIntToken((int)eTokenGridInt::position, selObj->AbsolutePosition); - } - - DrawBackground(); +void cBrowserGrid::SwitchGrid(int index) { + m_pHeader->Clear(); + m_pHeader->ClearTokens(); + m_pHeader->AddIntToken((int) eTokenGridInt::columns, m_columns); + m_pHeader->AddIntToken((int) eTokenGridInt::rows, m_rows); + m_pHeader->AddIntToken((int) eTokenGridInt::totalcount, m_vElements.size()); + + if (plexclient::plexgdm::GetInstance().GetFirstServer()) { + if (m_viewEntryIndex < (int) Config::GetInstance().m_viewentries.size()) { + ViewEntry entry = Config::GetInstance().m_viewentries[index]; + m_pHeader->AddStringToken((int) eTokenGridStr::tabname, tr(entry.Name.c_str())); + m_pService = std::shared_ptr<plexclient::Plexservice>( + new plexclient::Plexservice(plexclient::plexgdm::GetInstance().GetFirstServer(), entry.PlexPath)); + m_pContainer = m_pService->GetSection(m_pService->StartUri); + m_bServersAreRoot = false; + m_vServerElements.clear(); + } else { + //Server View + m_pHeader->AddStringToken((int) eTokenGridStr::tabname, tr("Library")); + m_pService = NULL; + m_pContainer = NULL; + m_bServersAreRoot = true; + SetServerElements(); + } + } else { + m_pHeader->AddStringToken((int) eTokenGridStr::tabname, tr("No Plex Media Server found.")); + m_pInfopane->AddStringToken((int) eTokenGridStr::title, tr("No Plex Media Server found.")); + m_pService = NULL; + m_pContainer = NULL; + } + ProcessData(); + auto selObj = SelectedObject(); + if (selObj) { + selObj->AddTokens(m_pHeader, false); + m_pHeader->AddIntToken((int) eTokenGridInt::position, selObj->AbsolutePosition); + } + + DrawBackground(); } -void cBrowserGrid::SetServerElements() -{ - m_vServerElements.clear(); +void cBrowserGrid::SetServerElements() { + m_vServerElements.clear(); - for(std::vector<plexclient::PlexServer>::iterator it = plexclient::plexgdm::GetInstance().GetPlexservers().begin(); it != plexclient::plexgdm::GetInstance().GetPlexservers().end(); ++it) { - for(std::vector<ViewEntry>::iterator vEntry = Config::GetInstance().m_serverViewentries.begin(); vEntry != Config::GetInstance().m_serverViewentries.end(); ++vEntry) { - m_vServerElements.push_back(cServerElement(&(*it), vEntry->PlexPath, vEntry->Name)); - } - } + for (std::vector<plexclient::PlexServer>::iterator it = plexclient::plexgdm::GetInstance().GetPlexservers().begin(); + it != plexclient::plexgdm::GetInstance().GetPlexservers().end(); ++it) { + for (std::vector<ViewEntry>::iterator vEntry = Config::GetInstance().m_serverViewentries.begin(); + vEntry != Config::GetInstance().m_serverViewentries.end(); ++vEntry) { + m_vServerElements.push_back(cServerElement(&(*it), vEntry->PlexPath, vEntry->Name)); + } + } } -void cBrowserGrid::ProcessData() -{ - m_vElements.clear(); - - if(m_vServerElements.size() > 0) { - for(auto it = m_vServerElements.begin(); it !=m_vServerElements.end(); ++it) { - cServerElement *elem = &(*it); - m_vElements.push_back(elem); - } - } else if (m_pContainer) { - if (!m_pService->IsRoot()) { - m_vElements.push_back(&m_Dummy); - m_Dummy.Dirty(); - } - - if(m_pContainer->m_vVideos.size() > 0) { - for(std::vector<plexclient::cVideo>::iterator it = m_pContainer->m_vVideos.begin(); it != m_pContainer->m_vVideos.end(); ++it) { - plexclient::cVideo *elem = &(*it); - m_vElements.push_back(elem); - } - } - if(m_pContainer->m_vDirectories.size() > 0) { - for(std::vector<plexclient::Directory>::iterator it = m_pContainer->m_vDirectories.begin(); it != m_pContainer->m_vDirectories.end(); ++it) { - plexclient::Directory *elem = &(*it); - m_vElements.push_back(elem); - } - } - } - - int pos = 0; - for(std::vector<cGridElement*>::iterator it = m_vElements.begin(); it != m_vElements.end(); ++it) { - cGridElement *elem = *it; - elem->AbsolutePosition = pos++; - } - - m_startIndex = 0; - - m_pGrid->Clear(); - m_setIterator = true; - FilterElements(0); +void cBrowserGrid::ProcessData() { + m_vElements.clear(); + + if (m_vServerElements.size() > 0) { + for (auto it = m_vServerElements.begin(); it != m_vServerElements.end(); ++it) { + cServerElement *elem = &(*it); + m_vElements.push_back(elem); + } + } else if (m_pContainer) { + if (!m_pService->IsRoot()) { + m_vElements.push_back(&m_Dummy); + m_Dummy.Dirty(); + } + + if (m_pContainer->m_vVideos.size() > 0) { + for (std::vector<plexclient::cVideo>::iterator it = m_pContainer->m_vVideos.begin(); + it != m_pContainer->m_vVideos.end(); ++it) { + plexclient::cVideo *elem = &(*it); + m_vElements.push_back(elem); + } + } + if (m_pContainer->m_vDirectories.size() > 0) { + for (std::vector<plexclient::Directory>::iterator it = m_pContainer->m_vDirectories.begin(); + it != m_pContainer->m_vDirectories.end(); ++it) { + plexclient::Directory *elem = &(*it); + m_vElements.push_back(elem); + } + } + } + + int pos = 0; + for (std::vector<cGridElement *>::iterator it = m_vElements.begin(); it != m_vElements.end(); ++it) { + cGridElement *elem = *it; + elem->AbsolutePosition = pos++; + } + + m_startIndex = 0; + + m_pGrid->Clear(); + m_setIterator = true; + FilterElements(0); } -eOSState cBrowserGrid::NavigateSelect() -{ - if(m_setIterator) return eOSState::osContinue;; - plexclient::Directory* dir = dynamic_cast<plexclient::Directory*>(SelectedObject()); - if(dir) { - m_pContainer = m_pService->GetSection(dir->m_sKey); - ProcessData(); - return eOSState::osContinue; - } else if(dynamic_cast<cDummyElement*>(SelectedObject())) { - return NavigateBack(); - } else if(cServerElement* srv = dynamic_cast<cServerElement*>(SelectedObject())) { - m_pService = std::shared_ptr<plexclient::Plexservice>(new plexclient::Plexservice( srv->Server() ) ); - m_pContainer = m_pService->GetSection(srv->StartPath()); - m_vServerElements.clear(); - ProcessData(); - return eOSState::osContinue; - } else if(dynamic_cast<plexclient::cVideo*>(SelectedObject())) { - return eOSState::osUser1; - } else return eOSState::osEnd; +eOSState cBrowserGrid::NavigateSelect() { + if (m_setIterator) return eOSState::osContinue;; + plexclient::Directory *dir = dynamic_cast<plexclient::Directory *>(SelectedObject()); + if (dir) { + m_pContainer = m_pService->GetSection(dir->m_sKey); + ProcessData(); + return eOSState::osContinue; + } else if (dynamic_cast<cDummyElement *>(SelectedObject())) { + return NavigateBack(); + } else if (cServerElement *srv = dynamic_cast<cServerElement *>(SelectedObject())) { + m_pService = std::shared_ptr<plexclient::Plexservice>(new plexclient::Plexservice(srv->Server())); + m_pContainer = m_pService->GetSection(srv->StartPath()); + m_vServerElements.clear(); + ProcessData(); + return eOSState::osContinue; + } else if (dynamic_cast<plexclient::cVideo *>(SelectedObject())) { + return eOSState::osUser1; + } else return eOSState::osEnd; } -eOSState cBrowserGrid::NavigateBack() -{ - if(m_setIterator) return eOSState::osContinue;; - std::shared_ptr<plexclient::MediaContainer> pCont = NULL; - if(m_pService) { - pCont = m_pService->GetLastSection(); - } - - if(pCont) { - m_pContainer = pCont; - ProcessData(); - return eOSState::osContinue; - - } else if(m_bServersAreRoot && m_pService) { - m_pContainer = NULL; - m_pService = NULL; - SetServerElements(); - ProcessData(); - return eOSState::osContinue; - } - return eOSState::osEnd; +eOSState cBrowserGrid::NavigateBack() { + if (m_setIterator) return eOSState::osContinue;; + std::shared_ptr<plexclient::MediaContainer> pCont = NULL; + if (m_pService) { + pCont = m_pService->GetLastSection(); + } + + if (pCont) { + m_pContainer = pCont; + ProcessData(); + return eOSState::osContinue; + + } else if (m_bServersAreRoot && m_pService) { + m_pContainer = NULL; + m_pService = NULL; + SetServerElements(); + ProcessData(); + return eOSState::osContinue; + } + return eOSState::osEnd; } -void cBrowserGrid::DrawGrid() -{ - m_pHeader->Display(); - DrawInfopane(); - DrawFooter(); - DrawScrollbar(); +void cBrowserGrid::DrawGrid() { + m_pHeader->Display(); + DrawInfopane(); + DrawFooter(); + DrawScrollbar(); } -void cBrowserGrid::DrawBackground() -{ - m_redrawBackground = true; - m_pBackground->ClearTokens(); - - /*auto video = dynamic_cast<plexclient::Video*>(SelectedObject()); - if(video) { - bool cached = false; - std::string path = cPictureCache::GetInstance().GetPath(video->ArtUri(), 1920, 1080, cached); - m_pBackground->AddStringToken("selecteditembackground", path); - } - */ - m_pBackground->AddIntToken((int)eTokenBackgroundInt::isdirectory, 1); - m_pBackground->AddStringToken((int)eTokenBackgroundStr::currentdirectorybackground, "/path"); - m_pBackground->AddIntToken((int)eTokenBackgroundInt::viewmode, Config::GetInstance().DefaultViewMode); +void cBrowserGrid::DrawBackground() { + m_redrawBackground = true; + m_pBackground->ClearTokens(); + + /*auto video = dynamic_cast<plexclient::Video*>(SelectedObject()); + if(video) { + bool cached = false; + std::string path = cPictureCache::GetInstance().GetPath(video->ArtUri(), 1920, 1080, cached); + m_pBackground->AddStringToken("selecteditembackground", path); + } + */ + m_pBackground->AddIntToken((int) eTokenBackgroundInt::isdirectory, 1); + m_pBackground->AddStringToken((int) eTokenBackgroundStr::currentdirectorybackground, "/path"); + m_pBackground->AddIntToken((int) eTokenBackgroundInt::viewmode, Config::GetInstance().DefaultViewMode); } -void cBrowserGrid::DrawInfopane() -{ - m_pInfopane->Clear(); - if(SelectedObject()) { - SelectedObject()->AddTokens(m_pInfopane, true); - m_pInfopane->AddIntToken((int)eTokenGridInt::columns, m_columns); - m_pInfopane->AddIntToken((int)eTokenGridInt::rows, m_rows); - m_pInfopane->AddIntToken((int)eTokenGridInt::totalcount, m_vElements.size()); - m_pInfopane->AddIntToken((int)eTokenGridInt::position, SelectedObject()->AbsolutePosition); - } - m_pInfopane->Display(); +void cBrowserGrid::DrawInfopane() { + m_pInfopane->Clear(); + if (SelectedObject()) { + SelectedObject()->AddTokens(m_pInfopane, true); + m_pInfopane->AddIntToken((int) eTokenGridInt::columns, m_columns); + m_pInfopane->AddIntToken((int) eTokenGridInt::rows, m_rows); + m_pInfopane->AddIntToken((int) eTokenGridInt::totalcount, m_vElements.size()); + m_pInfopane->AddIntToken((int) eTokenGridInt::position, SelectedObject()->AbsolutePosition); + } + m_pInfopane->Display(); } -void cBrowserGrid::DrawFooter() -{ - //if (!active) - // return; - cString nextTab = "Library"; - if(m_viewEntryIndex + 1 < (int)Config::GetInstance().m_viewentries.size()) { - nextTab = Config::GetInstance().m_viewentries[m_viewEntryIndex + 1].Name.c_str(); - } else if(m_viewEntryIndex + 1 == (int)Config::GetInstance().m_viewentries.size() + 1) { - nextTab = Config::GetInstance().m_viewentries[0].Name.c_str(); - } - cString details = "Details"; +void cBrowserGrid::DrawFooter() { + //if (!active) + // return; + cString nextTab = "Library"; + if (m_viewEntryIndex + 1 < (int) Config::GetInstance().m_viewentries.size()) { + nextTab = Config::GetInstance().m_viewentries[m_viewEntryIndex + 1].Name.c_str(); + } else if (m_viewEntryIndex + 1 == (int) Config::GetInstance().m_viewentries.size() + 1) { + nextTab = Config::GetInstance().m_viewentries[0].Name.c_str(); + } + cString details = "Details"; - string textGreen = tr(details); - string textYellow = tr(nextTab); - string textRed = ""; - string textBlue = tr("Switch View"); + string textGreen = tr(details); + string textYellow = tr(nextTab); + string textRed = ""; + string textBlue = tr("Switch View"); - if(auto vid = dynamic_cast<plexclient::cVideo*>(SelectedObject()) ) { - if(vid->m_iViewCount > 0) textRed = tr("Unscrobble"); - else textRed = tr("Scrobble"); - } + if (auto vid = dynamic_cast<plexclient::cVideo *>(SelectedObject())) { + if (vid->m_iViewCount > 0) textRed = tr("Unscrobble"); + else textRed = tr("Scrobble"); + } - int colorKeys[4] = { Setup.ColorKey0, Setup.ColorKey1, Setup.ColorKey2, Setup.ColorKey3 }; + int colorKeys[4] = {Setup.ColorKey0, Setup.ColorKey1, Setup.ColorKey2, Setup.ColorKey3}; - m_pfooter->Clear(); - m_pfooter->ClearTokens(); + m_pfooter->Clear(); + m_pfooter->ClearTokens(); - m_pfooter->AddStringToken((int)eTokenFooterStr::red, textRed.c_str()); - m_pfooter->AddStringToken((int)eTokenFooterStr::green, textGreen.c_str()); - m_pfooter->AddStringToken((int)eTokenFooterStr::yellow, textYellow.c_str()); - m_pfooter->AddStringToken((int)eTokenFooterStr::blue, textBlue.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::red, textRed.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::green, textGreen.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::yellow, textYellow.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::blue, textBlue.c_str()); for (int button = 0; button < 4; button++) { bool isRed = false; @@ -343,146 +338,137 @@ void cBrowserGrid::DrawFooter() default: break; } - m_pfooter->AddIntToken(0 + button, isRed); - m_pfooter->AddIntToken(4 + button, isGreen); - m_pfooter->AddIntToken(8 + button, isYellow); + m_pfooter->AddIntToken(0 + button, isRed); + m_pfooter->AddIntToken(4 + button, isGreen); + m_pfooter->AddIntToken(8 + button, isYellow); m_pfooter->AddIntToken(12 + button, isBlue); } - m_pfooter->Display(); + m_pfooter->Display(); } -void cBrowserGrid::DrawScrollbar() -{ - m_pScrollbar->Clear(); - m_pScrollbar->ClearTokens(); - - if ((int)m_vElements.size() > (m_columns * m_rows)) { - int currentRow = SelectedObject()->AbsolutePosition / m_columns; - int totalRows = ceil((double) m_vElements.size() / m_columns); - - int scrollBarHeight = 100.0 / totalRows * m_rows; - - int offset = 100.0 / totalRows * currentRow; - if(offset >= 100 - scrollBarHeight) { - offset = 100.0 - scrollBarHeight; - } - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::height, scrollBarHeight); - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::offset, offset); - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::hasscrollbar, true); - } else { - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::hasscrollbar, false); - } - - m_pScrollbar->Display(); +void cBrowserGrid::DrawScrollbar() { + m_pScrollbar->Clear(); + m_pScrollbar->ClearTokens(); + + if ((int) m_vElements.size() > (m_columns * m_rows)) { + int currentRow = SelectedObject()->AbsolutePosition / m_columns; + int totalRows = ceil((double) m_vElements.size() / m_columns); + + int scrollBarHeight = 100.0 / totalRows * m_rows; + + int offset = 100.0 / totalRows * currentRow; + if (offset >= 100 - scrollBarHeight) { + offset = 100.0 - scrollBarHeight; + } + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::height, scrollBarHeight); + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::offset, offset); + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::hasscrollbar, true); + } else { + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::hasscrollbar, false); + } + + m_pScrollbar->Display(); } -void cBrowserGrid::NextTab() -{ - m_viewEntryIndex++; - if(m_viewEntryIndex > (int)Config::GetInstance().m_viewentries.size()) { - m_viewEntryIndex = 0; - } - SwitchGrid(m_viewEntryIndex); +void cBrowserGrid::NextTab() { + m_viewEntryIndex++; + if (m_viewEntryIndex > (int) Config::GetInstance().m_viewentries.size()) { + m_viewEntryIndex = 0; + } + SwitchGrid(m_viewEntryIndex); } -void cBrowserGrid::PrevTab() -{ - m_viewEntryIndex--; - if(m_viewEntryIndex < 0) { - m_viewEntryIndex = Config::GetInstance().m_viewentries.size(); - } - SwitchGrid(m_viewEntryIndex); +void cBrowserGrid::PrevTab() { + m_viewEntryIndex--; + if (m_viewEntryIndex < 0) { + m_viewEntryIndex = Config::GetInstance().m_viewentries.size(); + } + SwitchGrid(m_viewEntryIndex); } -bool cBrowserGrid::DrawTime() -{ - time_t t = time(0); // get time now - struct tm * now = localtime(&t); - int sec = now->tm_sec; - if (sec == m_lastsecond) - return false; - - int min = now->tm_min; - int hour = now->tm_hour; - int hourMinutes = hour%12 * 5 + min / 12; - - char monthname[20]; - char monthshort[10]; - strftime(monthshort, sizeof(monthshort), "%b", now); - strftime(monthname, sizeof(monthname), "%B", now); - - m_pWatch->Clear(); - m_pWatch->ClearTokens(); - m_pWatch->AddIntToken((int)eTokenTimeInt::sec, sec); - m_pWatch->AddIntToken((int)eTokenTimeInt::min, min); - m_pWatch->AddIntToken((int)eTokenTimeInt::hour, hour); - m_pWatch->AddIntToken((int)eTokenTimeInt::hmins, hourMinutes); - m_pWatch->AddIntToken((int)eTokenTimeInt::year, now->tm_year + 1900); - m_pWatch->AddIntToken((int)eTokenTimeInt::day, now->tm_mday); - m_pWatch->AddStringToken((int)eTokenTimeStr::time, *TimeString(t)); - m_pWatch->AddStringToken((int)eTokenTimeStr::monthname, monthname); - m_pWatch->AddStringToken((int)eTokenTimeStr::monthnameshort, monthshort); - m_pWatch->AddStringToken((int)eTokenTimeStr::month, *cString::sprintf("%02d", now->tm_mon + 1)); - m_pWatch->AddStringToken((int)eTokenTimeStr::dayleadingzero, *cString::sprintf("%02d", now->tm_mday)); - m_pWatch->AddStringToken((int)eTokenTimeStr::dayname, *WeekDayNameFull(now->tm_wday)); - m_pWatch->AddStringToken((int)eTokenTimeStr::daynameshort, *WeekDayName(now->tm_wday)); - m_pWatch->Display(); - - m_lastsecond = sec; - return true; +bool cBrowserGrid::DrawTime() { + time_t t = time(0); // get time now + struct tm *now = localtime(&t); + int sec = now->tm_sec; + if (sec == m_lastsecond) + return false; + + int min = now->tm_min; + int hour = now->tm_hour; + int hourMinutes = hour % 12 * 5 + min / 12; + + char monthname[20]; + char monthshort[10]; + strftime(monthshort, sizeof(monthshort), "%b", now); + strftime(monthname, sizeof(monthname), "%B", now); + + m_pWatch->Clear(); + m_pWatch->ClearTokens(); + m_pWatch->AddIntToken((int) eTokenTimeInt::sec, sec); + m_pWatch->AddIntToken((int) eTokenTimeInt::min, min); + m_pWatch->AddIntToken((int) eTokenTimeInt::hour, hour); + m_pWatch->AddIntToken((int) eTokenTimeInt::hmins, hourMinutes); + m_pWatch->AddIntToken((int) eTokenTimeInt::year, now->tm_year + 1900); + m_pWatch->AddIntToken((int) eTokenTimeInt::day, now->tm_mday); + m_pWatch->AddStringToken((int) eTokenTimeStr::time, *TimeString(t)); + m_pWatch->AddStringToken((int) eTokenTimeStr::monthname, monthname); + m_pWatch->AddStringToken((int) eTokenTimeStr::monthnameshort, monthshort); + m_pWatch->AddStringToken((int) eTokenTimeStr::month, *cString::sprintf("%02d", now->tm_mon + 1)); + m_pWatch->AddStringToken((int) eTokenTimeStr::dayleadingzero, *cString::sprintf("%02d", now->tm_mday)); + m_pWatch->AddStringToken((int) eTokenTimeStr::dayname, *WeekDayNameFull(now->tm_wday)); + m_pWatch->AddStringToken((int) eTokenTimeStr::daynameshort, *WeekDayName(now->tm_wday)); + m_pWatch->Display(); + + m_lastsecond = sec; + return true; } /* * cDummyElement */ -cDummyElement::cDummyElement() -{ - m_title = "../"; +cDummyElement::cDummyElement() { + m_title = "../"; } -cDummyElement::cDummyElement(std::string title) -{ - m_title = title; +cDummyElement::cDummyElement(std::string title) { + m_title = title; } -void cDummyElement::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, std::function<void(cGridElement*)> OnCached) -{ - if(clear) grid->ClearTokens(); - grid->AddIntToken((int)eTokenGridInt::isdummy, 1); - grid->AddStringToken((int)eTokenGridStr::title, m_title.c_str()); +void cDummyElement::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, + std::function<void(cGridElement *)> OnCached) { + if (clear) grid->ClearTokens(); + grid->AddIntToken((int) eTokenGridInt::isdummy, 1); + grid->AddStringToken((int) eTokenGridStr::title, m_title.c_str()); } -std::string cDummyElement::GetTitle() -{ - return "Dummy"; +std::string cDummyElement::GetTitle() { + return "Dummy"; } /* * cServerElement */ -cServerElement::cServerElement(plexclient::PlexServer* server, std::string startPath, std::string startName) -{ - m_pServer = server; - m_sStartPath = startPath; - m_sStartName = startName; +cServerElement::cServerElement(plexclient::PlexServer *server, std::string startPath, std::string startName) { + m_pServer = server; + m_sStartPath = startPath; + m_sStartName = startName; } -void cServerElement::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, std::function<void(cGridElement*)> OnCached) -{ - if(clear) grid->ClearTokens(); - grid->AddIntToken((int)eTokenGridInt::isserver, 1); - grid->AddStringToken((int)eTokenGridStr::title, m_pServer->GetServerName().c_str()); - grid->AddStringToken((int)eTokenGridStr::serverstartpointname, m_sStartName.c_str()); - grid->AddStringToken((int)eTokenGridStr::serverip, m_pServer->GetHost().c_str()); - grid->AddIntToken((int)eTokenGridInt::serverport, m_pServer->GetPort()); - grid->AddStringToken((int)eTokenGridStr::serverversion, m_pServer->GetVersion().c_str()); - grid->AddIntToken((int)eTokenGridInt::viewmode, Config::GetInstance().DefaultViewMode); +void cServerElement::AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear, + std::function<void(cGridElement *)> OnCached) { + if (clear) grid->ClearTokens(); + grid->AddIntToken((int) eTokenGridInt::isserver, 1); + grid->AddStringToken((int) eTokenGridStr::title, m_pServer->GetServerName().c_str()); + grid->AddStringToken((int) eTokenGridStr::serverstartpointname, m_sStartName.c_str()); + grid->AddStringToken((int) eTokenGridStr::serverip, m_pServer->GetHost().c_str()); + grid->AddIntToken((int) eTokenGridInt::serverport, m_pServer->GetPort()); + grid->AddStringToken((int) eTokenGridStr::serverversion, m_pServer->GetVersion().c_str()); + grid->AddIntToken((int) eTokenGridInt::viewmode, Config::GetInstance().DefaultViewMode); } -std::string cServerElement::GetTitle() -{ - return "Server"; +std::string cServerElement::GetTitle() { + return "Server"; } diff --git a/browserGrid.h b/browserGrid.h index 12b35f8..19cd501 100644 --- a/browserGrid.h +++ b/browserGrid.h @@ -11,76 +11,99 @@ //#include "viewHeader.h" #include <libskindesignerapi/osdelements.h> -class cDummyElement : public cGridElement -{ +class cDummyElement : public cGridElement { private: - std::string m_title; + std::string m_title; public: - cDummyElement(std::string title); - cDummyElement(); - virtual std::string GetTitle(); - virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, std::function<void(cGridElement*)> OnCached = NULL); + cDummyElement(std::string title); + + cDummyElement(); + + virtual std::string GetTitle(); + + virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, + std::function<void(cGridElement *)> OnCached = NULL); }; -class cServerElement : public cGridElement -{ +class cServerElement : public cGridElement { private: - plexclient::PlexServer* m_pServer; - std::string m_sStartPath; - std::string m_sStartName; + plexclient::PlexServer *m_pServer; + std::string m_sStartPath; + std::string m_sStartName; public: - cServerElement(plexclient::PlexServer* server, std::string startPath, std::string startName); - virtual std::string GetTitle(); - virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, std::function<void(cGridElement*)> OnCached = NULL); - std::string StartPath() { return m_sStartPath; } - plexclient::PlexServer* Server() { return m_pServer; } + cServerElement(plexclient::PlexServer *server, std::string startPath, std::string startName); + + virtual std::string GetTitle(); + + virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> grid, bool clear = true, + std::function<void(cGridElement *)> OnCached = NULL); + + std::string StartPath() { return m_sStartPath; } + + plexclient::PlexServer *Server() { return m_pServer; } }; -class cBrowserGrid : public cViewGridNavigator -{ +class cBrowserGrid : public cViewGridNavigator { private: - //std::shared_ptr<cViewHeader> m_pViewHeader; - std::shared_ptr<skindesignerapi::cViewElement> m_pHeader; - std::shared_ptr<skindesignerapi::cViewElement> m_pBackground; - std::shared_ptr<skindesignerapi::cViewElement> m_pfooter; - std::shared_ptr<skindesignerapi::cViewElement> m_pInfopane; - std::shared_ptr<skindesignerapi::cViewElement> m_pScrollbar; - std::shared_ptr<skindesignerapi::cViewElement> m_pWatch; - int m_lastsecond; - int m_viewEntryIndex; - bool m_redrawBackground; - - bool m_bServersAreRoot; - std::vector<cServerElement> m_vServerElements; - std::shared_ptr<plexclient::MediaContainer> m_pContainer; - std::shared_ptr<plexclient::Plexservice> m_pService; - cDummyElement m_Dummy; - - void ProcessData(); - void SetServerElements(); - void DrawFooter(); - void DrawBackground(); - void DrawInfopane(); - void DrawScrollbar(); + //std::shared_ptr<cViewHeader> m_pViewHeader; + std::shared_ptr<skindesignerapi::cViewElement> m_pHeader; + std::shared_ptr<skindesignerapi::cViewElement> m_pBackground; + std::shared_ptr<skindesignerapi::cViewElement> m_pfooter; + std::shared_ptr<skindesignerapi::cViewElement> m_pInfopane; + std::shared_ptr<skindesignerapi::cViewElement> m_pScrollbar; + std::shared_ptr<skindesignerapi::cViewElement> m_pWatch; + int m_lastsecond; + int m_viewEntryIndex; + bool m_redrawBackground; + + bool m_bServersAreRoot; + std::vector<cServerElement> m_vServerElements; + std::shared_ptr<plexclient::MediaContainer> m_pContainer; + std::shared_ptr<plexclient::Plexservice> m_pService; + cDummyElement m_Dummy; + + void ProcessData(); + + void SetServerElements(); + + void DrawFooter(); + + void DrawBackground(); + + void DrawInfopane(); + + void DrawScrollbar(); public: - cBrowserGrid(std::shared_ptr<skindesignerapi::cOsdView> rootView); - ~cBrowserGrid(); - //cBrowserGrid(skindesignerapi::cViewGrid* viewGrid, std::shared_ptr<plexclient::Plexservice> service); - std::shared_ptr<plexclient::MediaContainer> MediaContainer() { return m_pContainer; } - - void DrawGrid(); - void SwitchGrid(int index); - void SwitchView(ViewMode mode = Config::GetInstance().DefaultViewMode); - void NextViewMode(); - virtual eOSState NavigateSelect(); - virtual eOSState NavigateBack(); - void NextTab(); - void PrevTab(); - bool DrawTime(); - virtual void Flush(); - virtual void Clear(); + cBrowserGrid(std::shared_ptr<skindesignerapi::cOsdView> rootView); + + ~cBrowserGrid(); + + //cBrowserGrid(skindesignerapi::cViewGrid* viewGrid, std::shared_ptr<plexclient::Plexservice> service); + std::shared_ptr<plexclient::MediaContainer> MediaContainer() { return m_pContainer; } + + void DrawGrid(); + + void SwitchGrid(int index); + + void SwitchView(ViewMode mode = Config::GetInstance().DefaultViewMode); + + void NextViewMode(); + + virtual eOSState NavigateSelect(); + + virtual eOSState NavigateBack(); + + void NextTab(); + + void PrevTab(); + + bool DrawTime(); + + virtual void Flush(); + + virtual void Clear(); }; #endif // CBROWSERGRID_H diff --git a/cPlexOsdItem.cpp b/cPlexOsdItem.cpp index 4e4272f..de8e4fc 100644 --- a/cPlexOsdItem.cpp +++ b/cPlexOsdItem.cpp @@ -1,45 +1,45 @@ #include "cPlexOsdItem.h" -cPlexOsdItem::cPlexOsdItem(const char* title) :cOsdItem(title) { - m_bVideo = false; - m_bDir = false; +cPlexOsdItem::cPlexOsdItem(const char *title) : cOsdItem(title) { + m_bVideo = false; + m_bDir = false; } -cPlexOsdItem::cPlexOsdItem(const char* title, std::shared_ptr<plexclient::Plexservice> service) :cOsdItem(title) { - pservice = service; - m_bVideo = false; - m_bDir = false; +cPlexOsdItem::cPlexOsdItem(const char *title, std::shared_ptr<plexclient::Plexservice> service) : cOsdItem(title) { + pservice = service; + m_bVideo = false; + m_bDir = false; } -cPlexOsdItem::cPlexOsdItem(const char* title, plexclient::cVideo* obj) :cOsdItem(title) { - item = obj; - m_bVideo = true; - m_bDir = false; +cPlexOsdItem::cPlexOsdItem(const char *title, plexclient::cVideo *obj) : cOsdItem(title) { + item = obj; + m_bVideo = true; + m_bDir = false; } -cPlexOsdItem::cPlexOsdItem(const char* title, plexclient::Directory* obj) :cOsdItem(title) { - dir = obj; - m_bDir = true; - m_bVideo = false; +cPlexOsdItem::cPlexOsdItem(const char *title, plexclient::Directory *obj) : cOsdItem(title) { + dir = obj; + m_bDir = true; + m_bVideo = false; } -cPlexOsdItem::cPlexOsdItem(const char* title, plexclient::Stream* obj) :cOsdItem(title) { - stream = *obj; - dir = NULL; - item = NULL; - pservice = NULL; - m_bVideo = false; - m_bDir = false; +cPlexOsdItem::cPlexOsdItem(const char *title, plexclient::Stream *obj) : cOsdItem(title) { + stream = *obj; + dir = NULL; + item = NULL; + pservice = NULL; + m_bVideo = false; + m_bDir = false; } -plexclient::cVideo* cPlexOsdItem::GetAttachedVideo() { - return item; +plexclient::cVideo *cPlexOsdItem::GetAttachedVideo() { + return item; } -plexclient::Directory* cPlexOsdItem::GetAttachedDirectory() { - return dir; +plexclient::Directory *cPlexOsdItem::GetAttachedDirectory() { + return dir; } std::shared_ptr<plexclient::Plexservice> cPlexOsdItem::GetAttachedService() { - return pservice; + return pservice; } diff --git a/cPlexOsdItem.h b/cPlexOsdItem.h index b5e834f..195be97 100644 --- a/cPlexOsdItem.h +++ b/cPlexOsdItem.h @@ -12,42 +12,50 @@ #include "Directory.h" #include "Plexservice.h" -class cPlexOsdItem : public cOsdItem -{ +class cPlexOsdItem : public cOsdItem { private: - plexclient::cVideo* item; - plexclient::Directory* dir; - plexclient::Stream stream; - std::shared_ptr<plexclient::Plexservice> pservice; - bool m_bVideo; - bool m_bDir; + plexclient::cVideo *item; + plexclient::Directory *dir; + plexclient::Stream stream; + std::shared_ptr<plexclient::Plexservice> pservice; + bool m_bVideo; + bool m_bDir; public: - cPlexOsdItem(const char* title); - cPlexOsdItem(const char* title, std::shared_ptr<plexclient::Plexservice> service); - cPlexOsdItem(const char* title, plexclient::cVideo* obj); - cPlexOsdItem(const char* title, plexclient::Directory* obj); + cPlexOsdItem(const char *title); + + cPlexOsdItem(const char *title, std::shared_ptr<plexclient::Plexservice> service); + + cPlexOsdItem(const char *title, plexclient::cVideo *obj); + + cPlexOsdItem(const char *title, plexclient::Directory *obj); + /** * @brief * @param title Title * @param obj will be copied */ - cPlexOsdItem(const char* title, plexclient::Stream* obj); - plexclient::cVideo* GetAttachedVideo(); - plexclient::Directory* GetAttachedDirectory(); - plexclient::Stream& GetAttachedStream() { return stream; } - std::shared_ptr<plexclient::Plexservice> GetAttachedService(); - - bool IsVideo() const { - return m_bVideo; - } - bool IsDir() const { - return m_bDir; - } - - //virtual eOSState ProcessKey(eKeys Key); - //virtual void Set(void); - //virtual void SetMenuItem(cSkinDisplayMenu* DisplayMenu, int Index, bool Current, bool Selectable); + cPlexOsdItem(const char *title, plexclient::Stream *obj); + + plexclient::cVideo *GetAttachedVideo(); + + plexclient::Directory *GetAttachedDirectory(); + + plexclient::Stream &GetAttachedStream() { return stream; } + + std::shared_ptr<plexclient::Plexservice> GetAttachedService(); + + bool IsVideo() const { + return m_bVideo; + } + + bool IsDir() const { + return m_bDir; + } + + //virtual eOSState ProcessKey(eKeys Key); + //virtual void Set(void); + //virtual void SetMenuItem(cSkinDisplayMenu* DisplayMenu, int Index, bool Current, bool Selectable); }; #endif // CPLEXOSDITEM_H diff --git a/detailView.cpp b/detailView.cpp index 3055cb0..f44869d 100644 --- a/detailView.cpp +++ b/detailView.cpp @@ -2,102 +2,102 @@ #include "Config.h" cDetailView::cDetailView(std::shared_ptr<skindesignerapi::cOsdView> detailView, plexclient::cVideo *video) - : cViewGridNavigator(detailView) -{ - m_pBackground = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::background)); - m_pfooter = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::footer)); - m_pInfo = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::info)); - m_pScrollbar = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::scrollbar)); - m_pWatch = std::shared_ptr<skindesignerapi::cViewElement>(detailView->GetViewElement((int)eViewElementsDetail::watch)); - - m_pVideo = video; - m_drawall = true; - - m_pGrid = NULL; - SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid>(detailView->GetViewGrid((int)eViewDetailViewGrids::extras))); - SetGridDimensions(Config::GetInstance().ExtrasGridRows, Config::GetInstance().ExtrasGridColumns); - - m_vElements.clear(); - - int pos = 0; - for(auto it = m_pVideo->m_vExtras.begin(); it != m_pVideo->m_vExtras.end(); ++it) { - plexclient::cVideo *elem = &(*it); - elem->AbsolutePosition = pos++;; - m_vElements.push_back(elem); - } - - m_startIndex = 0; - - m_setIterator = true; - FilterElements(0); + : cViewGridNavigator(detailView) { + m_pBackground = std::shared_ptr<skindesignerapi::cViewElement>( + detailView->GetViewElement((int) eViewElementsDetail::background)); + m_pfooter = std::shared_ptr<skindesignerapi::cViewElement>( + detailView->GetViewElement((int) eViewElementsDetail::footer)); + m_pInfo = std::shared_ptr<skindesignerapi::cViewElement>( + detailView->GetViewElement((int) eViewElementsDetail::info)); + m_pScrollbar = std::shared_ptr<skindesignerapi::cViewElement>( + detailView->GetViewElement((int) eViewElementsDetail::scrollbar)); + m_pWatch = std::shared_ptr<skindesignerapi::cViewElement>( + detailView->GetViewElement((int) eViewElementsDetail::watch)); + + m_pVideo = video; + m_drawall = true; + + m_pGrid = NULL; + SetViewGrid( + std::shared_ptr<skindesignerapi::cViewGrid>(detailView->GetViewGrid((int) eViewDetailViewGrids::extras))); + SetGridDimensions(Config::GetInstance().ExtrasGridRows, Config::GetInstance().ExtrasGridColumns); + + m_vElements.clear(); + + int pos = 0; + for (auto it = m_pVideo->m_vExtras.begin(); it != m_pVideo->m_vExtras.end(); ++it) { + plexclient::cVideo *elem = &(*it); + elem->AbsolutePosition = pos++;; + m_vElements.push_back(elem); + } + + m_startIndex = 0; + + m_setIterator = true; + FilterElements(0); } -void cDetailView::Flush() -{ - if (m_drawall) { - m_pBackground->Display(); - m_pInfo->Display(); - m_drawall = false; - } - m_pfooter->Display(); - m_pGrid->Display(); - m_pScrollbar->Display(); - - m_pRootView->Display(); +void cDetailView::Flush() { + if (m_drawall) { + m_pBackground->Display(); + m_pInfo->Display(); + m_drawall = false; + } + m_pfooter->Display(); + m_pGrid->Display(); + m_pScrollbar->Display(); + + m_pRootView->Display(); } -void cDetailView::Draw() -{ - // Draw Grid - - DrawBackground(); - DrawFooter(); - DrawInfo(); - DrawScrollbar(); - DrawTime(); +void cDetailView::Draw() { + // Draw Grid + + DrawBackground(); + DrawFooter(); + DrawInfo(); + DrawScrollbar(); + DrawTime(); } -void cDetailView::Clear() -{ - m_pBackground->Clear(); - m_pInfo->Clear(); - m_pScrollbar->Clear(); - m_pfooter->Clear(); - m_pGrid->Clear(); - m_pWatch->Clear(); +void cDetailView::Clear() { + m_pBackground->Clear(); + m_pInfo->Clear(); + m_pScrollbar->Clear(); + m_pfooter->Clear(); + m_pGrid->Clear(); + m_pWatch->Clear(); } -void cDetailView::DrawBackground() -{ - m_pBackground->ClearTokens(); - bool art = m_pVideo->m_sArt.empty() == false; - m_pBackground->AddIntToken((int)eTokenDetailBackgroundInt::hasfanart, art); - if(art) m_pBackground->AddStringToken((int)eTokenDetailBackgroundStr::fanartpath, m_pVideo->m_sArt.c_str()); - - bool cover = m_pVideo->m_sThumb.empty() == false; - m_pBackground->AddIntToken((int)eTokenDetailBackgroundInt::hascover, cover); - if(cover) m_pBackground->AddStringToken((int)eTokenDetailBackgroundStr::coverpath, m_pVideo->m_sThumb.c_str()); +void cDetailView::DrawBackground() { + m_pBackground->ClearTokens(); + bool art = m_pVideo->m_sArt.empty() == false; + m_pBackground->AddIntToken((int) eTokenDetailBackgroundInt::hasfanart, art); + if (art) m_pBackground->AddStringToken((int) eTokenDetailBackgroundStr::fanartpath, m_pVideo->m_sArt.c_str()); + + bool cover = m_pVideo->m_sThumb.empty() == false; + m_pBackground->AddIntToken((int) eTokenDetailBackgroundInt::hascover, cover); + if (cover) m_pBackground->AddStringToken((int) eTokenDetailBackgroundStr::coverpath, m_pVideo->m_sThumb.c_str()); } -void cDetailView::DrawFooter() -{ - string textRed = tr("Play"); - string textGreen = tr("Rewind"); - string textYellow = ""; - string textBlue = ""; +void cDetailView::DrawFooter() { + string textRed = tr("Play"); + string textGreen = tr("Rewind"); + string textYellow = ""; + string textBlue = ""; - if(m_pVideo->m_iViewCount > 0) textYellow = tr("Unscrobble"); - else textYellow = tr("Scrobble"); + if (m_pVideo->m_iViewCount > 0) textYellow = tr("Unscrobble"); + else textYellow = tr("Scrobble"); - int colorKeys[4] = { Setup.ColorKey0, Setup.ColorKey1, Setup.ColorKey2, Setup.ColorKey3 }; + int colorKeys[4] = {Setup.ColorKey0, Setup.ColorKey1, Setup.ColorKey2, Setup.ColorKey3}; - m_pfooter->Clear(); - m_pfooter->ClearTokens(); + m_pfooter->Clear(); + m_pfooter->ClearTokens(); - m_pfooter->AddStringToken((int)eTokenFooterStr::red, textRed.c_str()); - m_pfooter->AddStringToken((int)eTokenFooterStr::green, textGreen.c_str()); - m_pfooter->AddStringToken((int)eTokenFooterStr::yellow, textYellow.c_str()); - m_pfooter->AddStringToken((int)eTokenFooterStr::blue, textBlue.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::red, textRed.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::green, textGreen.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::yellow, textYellow.c_str()); + m_pfooter->AddStringToken((int) eTokenFooterStr::blue, textBlue.c_str()); for (int button = 0; button < 4; button++) { bool isRed = false; @@ -120,96 +120,91 @@ void cDetailView::DrawFooter() default: break; } - m_pfooter->AddIntToken(0 + button, isRed); - m_pfooter->AddIntToken(4 + button, isGreen); - m_pfooter->AddIntToken(8 + button, isYellow); + m_pfooter->AddIntToken(0 + button, isRed); + m_pfooter->AddIntToken(4 + button, isGreen); + m_pfooter->AddIntToken(8 + button, isYellow); m_pfooter->AddIntToken(12 + button, isBlue); } - m_pfooter->Display(); + m_pfooter->Display(); } -void cDetailView::DrawInfo() -{ - m_pInfo->Clear(); - m_pVideo->AddTokens(m_pInfo, true); - m_pInfo->Display(); +void cDetailView::DrawInfo() { + m_pInfo->Clear(); + m_pVideo->AddTokens(m_pInfo, true); + m_pInfo->Display(); } -void cDetailView::DrawScrollbar() -{ - m_pScrollbar->Clear(); - m_pScrollbar->ClearTokens(); - - if ((int)m_vElements.size() > (m_columns * m_rows)) { - int currentRow = SelectedObject()->AbsolutePosition / m_columns; - int totalRows = ceil((double) m_vElements.size() / m_columns); - - int scrollBarHeight = 100.0 / totalRows * m_rows; - - int offset = 100.0 / totalRows * currentRow; - if(offset >= 100 - scrollBarHeight) { - offset = 100.0 - scrollBarHeight; - } - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::height, scrollBarHeight); - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::offset, offset); - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::hasscrollbar, true); - } else { - m_pScrollbar->AddIntToken((int)eTokenScrollbarInt::hasscrollbar, false); - } - - m_pScrollbar->Display(); +void cDetailView::DrawScrollbar() { + m_pScrollbar->Clear(); + m_pScrollbar->ClearTokens(); + + if ((int) m_vElements.size() > (m_columns * m_rows)) { + int currentRow = SelectedObject()->AbsolutePosition / m_columns; + int totalRows = ceil((double) m_vElements.size() / m_columns); + + int scrollBarHeight = 100.0 / totalRows * m_rows; + + int offset = 100.0 / totalRows * currentRow; + if (offset >= 100 - scrollBarHeight) { + offset = 100.0 - scrollBarHeight; + } + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::height, scrollBarHeight); + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::offset, offset); + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::hasscrollbar, true); + } else { + m_pScrollbar->AddIntToken((int) eTokenScrollbarInt::hasscrollbar, false); + } + + m_pScrollbar->Display(); } -bool cDetailView::DrawTime() -{ - time_t t = time(0); // get time now - struct tm * now = localtime(&t); - int sec = now->tm_sec; - if (sec == m_lastsecond) - return false; - - int min = now->tm_min; - int hour = now->tm_hour; - int hourMinutes = hour%12 * 5 + min / 12; - - char monthname[20]; - char monthshort[10]; - strftime(monthshort, sizeof(monthshort), "%b", now); - strftime(monthname, sizeof(monthname), "%B", now); - - m_pWatch->Clear(); - m_pWatch->ClearTokens(); - m_pWatch->AddIntToken((int)eTokenTimeInt::sec, sec); - m_pWatch->AddIntToken((int)eTokenTimeInt::min, min); - m_pWatch->AddIntToken((int)eTokenTimeInt::hour, hour); - m_pWatch->AddIntToken((int)eTokenTimeInt::hmins, hourMinutes); - m_pWatch->AddIntToken((int)eTokenTimeInt::year, now->tm_year + 1900); - m_pWatch->AddIntToken((int)eTokenTimeInt::day, now->tm_mday); - m_pWatch->AddStringToken((int)eTokenTimeStr::time, *TimeString(t)); - m_pWatch->AddStringToken((int)eTokenTimeStr::monthname, monthname); - m_pWatch->AddStringToken((int)eTokenTimeStr::monthnameshort, monthshort); - m_pWatch->AddStringToken((int)eTokenTimeStr::month, *cString::sprintf("%02d", now->tm_mon + 1)); - m_pWatch->AddStringToken((int)eTokenTimeStr::dayleadingzero, *cString::sprintf("%02d", now->tm_mday)); - m_pWatch->AddStringToken((int)eTokenTimeStr::dayname, *WeekDayNameFull(now->tm_wday)); - m_pWatch->AddStringToken((int)eTokenTimeStr::daynameshort, *WeekDayName(now->tm_wday)); - m_pWatch->Display(); - - m_lastsecond = sec; - return true; +bool cDetailView::DrawTime() { + time_t t = time(0); // get time now + struct tm *now = localtime(&t); + int sec = now->tm_sec; + if (sec == m_lastsecond) + return false; + + int min = now->tm_min; + int hour = now->tm_hour; + int hourMinutes = hour % 12 * 5 + min / 12; + + char monthname[20]; + char monthshort[10]; + strftime(monthshort, sizeof(monthshort), "%b", now); + strftime(monthname, sizeof(monthname), "%B", now); + + m_pWatch->Clear(); + m_pWatch->ClearTokens(); + m_pWatch->AddIntToken((int) eTokenTimeInt::sec, sec); + m_pWatch->AddIntToken((int) eTokenTimeInt::min, min); + m_pWatch->AddIntToken((int) eTokenTimeInt::hour, hour); + m_pWatch->AddIntToken((int) eTokenTimeInt::hmins, hourMinutes); + m_pWatch->AddIntToken((int) eTokenTimeInt::year, now->tm_year + 1900); + m_pWatch->AddIntToken((int) eTokenTimeInt::day, now->tm_mday); + m_pWatch->AddStringToken((int) eTokenTimeStr::time, *TimeString(t)); + m_pWatch->AddStringToken((int) eTokenTimeStr::monthname, monthname); + m_pWatch->AddStringToken((int) eTokenTimeStr::monthnameshort, monthshort); + m_pWatch->AddStringToken((int) eTokenTimeStr::month, *cString::sprintf("%02d", now->tm_mon + 1)); + m_pWatch->AddStringToken((int) eTokenTimeStr::dayleadingzero, *cString::sprintf("%02d", now->tm_mday)); + m_pWatch->AddStringToken((int) eTokenTimeStr::dayname, *WeekDayNameFull(now->tm_wday)); + m_pWatch->AddStringToken((int) eTokenTimeStr::daynameshort, *WeekDayName(now->tm_wday)); + m_pWatch->Display(); + + m_lastsecond = sec; + return true; } -eOSState cDetailView::NavigateSelect() -{ - if(m_setIterator) return eOSState::osContinue; - - if(dynamic_cast<plexclient::cVideo*>(SelectedObject())) { - return eOSState::osUser1; - } else return eOSState::osBack; +eOSState cDetailView::NavigateSelect() { + if (m_setIterator) return eOSState::osContinue; + + if (dynamic_cast<plexclient::cVideo *>(SelectedObject())) { + return eOSState::osUser1; + } else return eOSState::osBack; } -eOSState cDetailView::NavigateBack() -{ - if(m_setIterator) return eOSState::osContinue; - return eOSState::osBack; +eOSState cDetailView::NavigateBack() { + if (m_setIterator) return eOSState::osContinue; + return eOSState::osBack; } diff --git a/detailView.h b/detailView.h index 67f3234..bf0eb33 100644 --- a/detailView.h +++ b/detailView.h @@ -8,34 +8,42 @@ #include <libskindesignerapi/osdelements.h> #include <libskindesignerapi/skindesignerosdbase.h> -class cDetailView : public cViewGridNavigator -{ +class cDetailView : public cViewGridNavigator { public: - cDetailView(std::shared_ptr<skindesignerapi::cOsdView> detailView, plexclient::cVideo *video); - - void Draw(); - virtual void Flush(); - virtual eOSState NavigateSelect(); - virtual eOSState NavigateBack(); - plexclient::cVideo* GetVideo() { return m_pVideo; }; - virtual void Clear(); - bool DrawTime(); - + cDetailView(std::shared_ptr<skindesignerapi::cOsdView> detailView, plexclient::cVideo *video); + + void Draw(); + + virtual void Flush(); + + virtual eOSState NavigateSelect(); + + virtual eOSState NavigateBack(); + + plexclient::cVideo *GetVideo() { return m_pVideo; }; + + virtual void Clear(); + + bool DrawTime(); + private: - std::shared_ptr<skindesignerapi::cViewElement> m_pBackground; - std::shared_ptr<skindesignerapi::cViewElement> m_pfooter; - std::shared_ptr<skindesignerapi::cViewElement> m_pInfo; - std::shared_ptr<skindesignerapi::cViewElement> m_pScrollbar; - std::shared_ptr<skindesignerapi::cViewElement> m_pWatch; - - plexclient::cVideo *m_pVideo; - bool m_drawall; - int m_lastsecond; - - void DrawBackground(); - void DrawFooter(); - void DrawInfo(); - void DrawScrollbar(); + std::shared_ptr<skindesignerapi::cViewElement> m_pBackground; + std::shared_ptr<skindesignerapi::cViewElement> m_pfooter; + std::shared_ptr<skindesignerapi::cViewElement> m_pInfo; + std::shared_ptr<skindesignerapi::cViewElement> m_pScrollbar; + std::shared_ptr<skindesignerapi::cViewElement> m_pWatch; + + plexclient::cVideo *m_pVideo; + bool m_drawall; + int m_lastsecond; + + void DrawBackground(); + + void DrawFooter(); + + void DrawInfo(); + + void DrawScrollbar(); }; #endif // CDETAILVIEW_H @@ -1,61 +1,58 @@ #include "device.h" -namespace plexclient -{ - -Connection::Connection(Poco::XML::Node* pNode, Device* parent) -{ - m_pParent = parent; - - NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pChildNode = it.nextNode(); - - while(pChildNode) { - if(Poco::icompare(pChildNode->nodeName(), "Connection") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - - m_sProtocol = GetNodeValue(pAttribs->getNamedItem("protocol")); - m_sAddress = GetNodeValue(pAttribs->getNamedItem("address")); - m_iPort = GetNodeValueAsInt(pAttribs->getNamedItem("port")); - m_sUri = GetNodeValue(pAttribs->getNamedItem("uri")); - m_bLocal = GetNodeValueAsBool(pAttribs->getNamedItem("local")); - - pAttribs->release(); - } - pChildNode = it.nextNode(); - } -} - -Device::Device(Poco::XML::Node* pNode, MediaContainer* parent) -{ - m_pParent = parent; - - NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); - Poco::XML::Node* pChildNode = it.nextNode(); - - while(pChildNode) { - if(Poco::icompare(pChildNode->nodeName(), "Device") == 0) { - Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); - - m_sName = GetNodeValue(pAttribs->getNamedItem("name")); - m_sProduct = GetNodeValue(pAttribs->getNamedItem("product")); - m_sProvides = GetNodeValue(pAttribs->getNamedItem("provides")); - m_sClientIdentifier = GetNodeValue(pAttribs->getNamedItem("clientIdentifier")); - m_bOwned = GetNodeValueAsBool(pAttribs->getNamedItem("owned")); - m_sAccessToken = GetNodeValue(pAttribs->getNamedItem("accessToken")); - m_bHttpsRequired = GetNodeValueAsBool(pAttribs->getNamedItem("httpsRequired")); - m_bPublicAddressMatches = GetNodeValueAsBool(pAttribs->getNamedItem("publicAddressMatches")); - m_bPresence = GetNodeValueAsBool(pAttribs->getNamedItem("presence")); - m_sSourceTitle = GetNodeValue(pAttribs->getNamedItem("sourceTitle")); - - pAttribs->release(); - } else if(Poco::icompare(pChildNode->nodeName(), "Connection") == 0) { - m_vConnections.push_back(Connection(pChildNode, this)); - } - - pChildNode = it.nextNode(); - } -} +namespace plexclient { + + Connection::Connection(Poco::XML::Node *pNode, Device *parent) { + m_pParent = parent; + + NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pChildNode = it.nextNode(); + + while (pChildNode) { + if (Poco::icompare(pChildNode->nodeName(), "Connection") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + + m_sProtocol = GetNodeValue(pAttribs->getNamedItem("protocol")); + m_sAddress = GetNodeValue(pAttribs->getNamedItem("address")); + m_iPort = GetNodeValueAsInt(pAttribs->getNamedItem("port")); + m_sUri = GetNodeValue(pAttribs->getNamedItem("uri")); + m_bLocal = GetNodeValueAsBool(pAttribs->getNamedItem("local")); + + pAttribs->release(); + } + pChildNode = it.nextNode(); + } + } + + Device::Device(Poco::XML::Node *pNode, MediaContainer *parent) { + m_pParent = parent; + + NodeIterator it(pNode, Poco::XML::NodeFilter::SHOW_ALL); + Poco::XML::Node *pChildNode = it.nextNode(); + + while (pChildNode) { + if (Poco::icompare(pChildNode->nodeName(), "Device") == 0) { + Poco::XML::AutoPtr<Poco::XML::NamedNodeMap> pAttribs = pChildNode->attributes(); + + m_sName = GetNodeValue(pAttribs->getNamedItem("name")); + m_sProduct = GetNodeValue(pAttribs->getNamedItem("product")); + m_sProvides = GetNodeValue(pAttribs->getNamedItem("provides")); + m_sClientIdentifier = GetNodeValue(pAttribs->getNamedItem("clientIdentifier")); + m_bOwned = GetNodeValueAsBool(pAttribs->getNamedItem("owned")); + m_sAccessToken = GetNodeValue(pAttribs->getNamedItem("accessToken")); + m_bHttpsRequired = GetNodeValueAsBool(pAttribs->getNamedItem("httpsRequired")); + m_bPublicAddressMatches = GetNodeValueAsBool(pAttribs->getNamedItem("publicAddressMatches")); + m_bPresence = GetNodeValueAsBool(pAttribs->getNamedItem("presence")); + m_sSourceTitle = GetNodeValue(pAttribs->getNamedItem("sourceTitle")); + + pAttribs->release(); + } else if (Poco::icompare(pChildNode->nodeName(), "Connection") == 0) { + m_vConnections.push_back(Connection(pChildNode, this)); + } + + pChildNode = it.nextNode(); + } + } } @@ -14,45 +14,42 @@ #include "XmlObject.h" #include "MediaContainer.h" -namespace plexclient -{ -class Device; - -class Connection: private XmlObject -{ -public: - Connection(Poco::XML::Node* pNode, Device* parent); - - std::string m_sProtocol; - std::string m_sAddress; - int m_iPort; - std::string m_sUri; - bool m_bLocal; - - Device* m_pParent; - -}; - -class Device: private XmlObject -{ -public: - Device(Poco::XML::Node* pNode, MediaContainer* parent); - - std::string m_sName; - std::string m_sProduct; - std::string m_sProvides; - std::string m_sClientIdentifier; - bool m_bOwned; - std::string m_sAccessToken; - bool m_bHttpsRequired; - bool m_bPublicAddressMatches; - bool m_bPresence; - std::string m_sSourceTitle; - - std::vector<Connection> m_vConnections; - - MediaContainer* m_pParent; -}; +namespace plexclient { + class Device; + + class Connection : private XmlObject { + public: + Connection(Poco::XML::Node *pNode, Device *parent); + + std::string m_sProtocol; + std::string m_sAddress; + int m_iPort; + std::string m_sUri; + bool m_bLocal; + + Device *m_pParent; + + }; + + class Device : private XmlObject { + public: + Device(Poco::XML::Node *pNode, MediaContainer *parent); + + std::string m_sName; + std::string m_sProduct; + std::string m_sProvides; + std::string m_sClientIdentifier; + bool m_bOwned; + std::string m_sAccessToken; + bool m_bHttpsRequired; + bool m_bPublicAddressMatches; + bool m_bPresence; + std::string m_sSourceTitle; + + std::vector<Connection> m_vConnections; + + MediaContainer *m_pParent; + }; } diff --git a/displayReplaySD.cpp b/displayReplaySD.cpp index 0e4d01c..ff71e9a 100644 --- a/displayReplaySD.cpp +++ b/displayReplaySD.cpp @@ -1,43 +1,36 @@ #include "displayReplaySD.h" -cDisplayReplaySD::cDisplayReplaySD(plexclient::cVideo* video) : cSkindesignerOsdObject(GetPluginStruct()) -{ +cDisplayReplaySD::cDisplayReplaySD(plexclient::cVideo *video) : cSkindesignerOsdObject(GetPluginStruct()) { } -cDisplayReplaySD::~cDisplayReplaySD() -{ +cDisplayReplaySD::~cDisplayReplaySD() { } -skindesignerapi::cPluginStructure* cDisplayReplaySD::m_pPlugStructReplay = NULL; -skindesignerapi::cPluginStructure* cDisplayReplaySD::GetPluginStruct() -{ - if(m_pPlugStructReplay == NULL) { - m_pPlugStructReplay = new skindesignerapi::cPluginStructure(); - m_pPlugStructReplay->name = "plexreplay"; - m_pPlugStructReplay->libskindesignerAPIVersion = LIBSKINDESIGNERAPIVERSION; - m_pPlugStructReplay->RegisterRootView("root.xml"); - } - return m_pPlugStructReplay; +skindesignerapi::cPluginStructure *cDisplayReplaySD::m_pPlugStructReplay = NULL; + +skindesignerapi::cPluginStructure *cDisplayReplaySD::GetPluginStruct() { + if (m_pPlugStructReplay == NULL) { + m_pPlugStructReplay = new skindesignerapi::cPluginStructure(); + m_pPlugStructReplay->name = "plexreplay"; + m_pPlugStructReplay->libskindesignerAPIVersion = LIBSKINDESIGNERAPIVERSION; + m_pPlugStructReplay->RegisterRootView("root.xml"); + } + return m_pPlugStructReplay; } -void cDisplayReplaySD::Show(void) -{ +void cDisplayReplaySD::Show(void) { } -eOSState cDisplayReplaySD::ProcessKey(eKeys Key) -{ - return eOSState::osContinue; +eOSState cDisplayReplaySD::ProcessKey(eKeys Key) { + return eOSState::osContinue; } -void cDisplayReplaySD::Flush() -{ +void cDisplayReplaySD::Flush() { } -void cDisplayReplaySD::SetCurrent(const char* Current) -{ +void cDisplayReplaySD::SetCurrent(const char *Current) { } -void cDisplayReplaySD::SetMode(bool Play, bool Forward, int Speed) -{ +void cDisplayReplaySD::SetMode(bool Play, bool Forward, int Speed) { } diff --git a/displayReplaySD.h b/displayReplaySD.h index 8fc4593..e633e95 100644 --- a/displayReplaySD.h +++ b/displayReplaySD.h @@ -7,29 +7,33 @@ #include <libskindesignerapi/osdelements.h> #include <libskindesignerapi/skindesignerosdbase.h> -class cDisplayReplaySD : public skindesignerapi::cSkindesignerOsdObject -{ +class cDisplayReplaySD : public skindesignerapi::cSkindesignerOsdObject { private: - static skindesignerapi::cPluginStructure* m_pPlugStructReplay; - static skindesignerapi::cPluginStructure* GetPluginStruct(); - - std::shared_ptr<skindesignerapi::cOsdView> m_pRootView; - std::shared_ptr<skindesignerapi::cViewElement> m_pProgessbar; - std::shared_ptr<skindesignerapi::cViewElement> m_pBackground; - std::shared_ptr<skindesignerapi::cViewElement> m_pVideoinfo; - std::shared_ptr<skindesignerapi::cViewElement> m_pTranscodeinfo; - + static skindesignerapi::cPluginStructure *m_pPlugStructReplay; + + static skindesignerapi::cPluginStructure *GetPluginStruct(); + + std::shared_ptr<skindesignerapi::cOsdView> m_pRootView; + std::shared_ptr<skindesignerapi::cViewElement> m_pProgessbar; + std::shared_ptr<skindesignerapi::cViewElement> m_pBackground; + std::shared_ptr<skindesignerapi::cViewElement> m_pVideoinfo; + std::shared_ptr<skindesignerapi::cViewElement> m_pTranscodeinfo; + public: - cDisplayReplaySD(plexclient::cVideo* video); - ~cDisplayReplaySD(); - - virtual void Show(void); - virtual eOSState ProcessKey(eKeys Key); - - void Flush(); - void SetCurrent(const char *Current); - void SetMode(bool Play, bool Forward, int Speed); - + cDisplayReplaySD(plexclient::cVideo *video); + + ~cDisplayReplaySD(); + + virtual void Show(void); + + virtual eOSState ProcessKey(eKeys Key); + + void Flush(); + + void SetCurrent(const char *Current); + + void SetMode(bool Play, bool Forward, int Speed); + }; diff --git a/hlsPlayer.cpp b/hlsPlayer.cpp index 1ef8ada..fc0c7cb 100644 --- a/hlsPlayer.cpp +++ b/hlsPlayer.cpp @@ -21,726 +21,691 @@ const int BUFFERSIZE = 8192; //--- cHlsSegmentLoader -cHlsSegmentLoader::cHlsSegmentLoader(std::string startm3u8, plexclient::cVideo* pVideo) -{ - m_pVideo = pVideo; - m_newList = false; - m_bufferFilled = false; - m_lastLoadedSegment = 0; - m_segmentsToBuffer = 2; - m_streamlenght = 0; - m_lastSegmentSize = 0; - m_pBuffer = new uchar[BUFFERSIZE]; - - // Initialize members - m_pClientSession = NULL; - - m_ringBufferSize = MEGABYTE(1); - m_pRingbuffer = NULL; - - m_startUri = Poco::URI(startm3u8); - m_startParser = cM3u8Parser(); - m_indexParser = cM3u8Parser(); -} - -cHlsSegmentLoader::~cHlsSegmentLoader() -{ - // Stop Thread - Cancel(0); - - delete m_pClientSession; - delete[] m_pBuffer; - delete m_pRingbuffer; -} - -void cHlsSegmentLoader::SkipEmptySegments(int segmentDuration) -{ - pcrecpp::RE re("&offset=(\\d+)", pcrecpp::RE_Options(PCRE_CASELESS)); - int value; - re.PartialMatch(m_startUri.getQuery(), &value); - if (value > segmentDuration) { - m_lastLoadedSegment = (value / segmentDuration) - 1; - } -} - -bool cHlsSegmentLoader::LoadM3u8(std::string uri) -{ - //LOCK_THREAD; - m_startUri = Poco::URI(uri); - return (m_newList = true); -} - -void cHlsSegmentLoader::Action(void) -{ - if(!LoadLists()) return; - - m_ringBufferSize = MEGABYTE(Config::GetInstance().BufferSize); - - isyslog("[plex]%s Create Ringbuffer %d MB", __FUNCTION__, Config::GetInstance().BufferSize); - - m_pRingbuffer = new cRingBufferLinear(m_ringBufferSize, 2*TS_SIZE); - - while(Running()) { - if(m_newList) { - hlsMutex.Lock(); - m_bufferFilled = false; - m_lastLoadedSegment = 0; - LoadLists(); - m_newList = false; - m_pRingbuffer->Clear(); - isyslog("[plex] Ringbuffer Cleared, loading new segments"); - hlsMutex.Unlock(); - } - int count = 0; - m_pRingbuffer->Get(count); - if (!DoLoad() && count < TS_SIZE) { - isyslog("[plex] No further segments to load and buffer empty, end of stream!"); - Cancel(); - - } - cCondWait::SleepMs(3); - } - StopLoader(); -} - -bool cHlsSegmentLoader::LoadLists(void) -{ - if( LoadStartList() ) { - if( false == LoadIndexList() ) { - esyslog("[plex]LoadIndexList failed!"); - return false; - } - } else { - esyslog("[plex]LoadStartList failed!"); - return false; - } - return true; -} - -bool cHlsSegmentLoader::LoadIndexList(void) -{ - bool res = false; - try { - if(m_startParser.MasterPlaylist && m_startParser.vPlaylistItems.size() > 0) { - // Todo: make it universal, might only work for Plexmediaserver - ConnectToServer(); - - std::string startUri = m_startUri.toString(); - startUri = startUri.substr(0, startUri.find_last_of("/")+1); - - Poco::URI indexUri(startUri+m_startParser.vPlaylistItems[0].file); - - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, indexUri.getPath()); - AddHeader(request); - // same server - m_pClientSession->sendRequest(request); - - Poco::Net::HTTPResponse responseStart; - std::istream& indexFile = m_pClientSession->receiveResponse(responseStart); - - if(responseStart.getStatus() != 200) { - esyslog("[plex]%s Response Not Valid", __FUNCTION__); - Poco::StreamCopier::copyStream(indexFile, std::cout); - return res; - } - m_indexParser = cM3u8Parser(); - res = m_indexParser.Parse(indexFile); - - if(res) { - // Segment URI is relative to index.m3u8 - std::string path = indexUri.getPath(); - m_segmentUriPart = path.substr(0, path.find_last_of("/")+1); - } - if(m_indexParser.TargetDuration > 3) { - m_segmentsToBuffer = 2; - } else { - m_segmentsToBuffer = 3; - } - - SkipEmptySegments(m_indexParser.TargetDuration); - m_lastSegmentSize = 0; - - // Get stream lenght - m_streamlenght = 0; - for(unsigned int i = 0; i < m_indexParser.vPlaylistItems.size(); i++) { - m_streamlenght += m_indexParser.vPlaylistItems[i].length; - } - } - - } catch (Poco::Exception &exc) { - esyslog("[plex] %s %s", __FUNCTION__, exc.displayText().c_str()); - res = false; - } - return res; -} - -bool cHlsSegmentLoader::LoadStartList(void) -{ - bool res = false; - ConnectToServer(); - try { - dsyslog("[plex]%s %s", __FUNCTION__, m_startUri.toString().c_str()); - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, m_startUri.getPathAndQuery()); - AddHeader(request); - m_pClientSession->sendRequest(request); - - Poco::Net::HTTPResponse responseStart; - std::istream& startFile = m_pClientSession->receiveResponse(responseStart); - - if(responseStart.getStatus() != 200) { - esyslog("[plex]%s Response Not Valid", __FUNCTION__); - Poco::StreamCopier::copyStream(startFile, std::cout); - return res; - } - - m_startParser = cM3u8Parser(); - res = m_startParser.Parse(startFile); - if(res) { - // Get GUID - pcrecpp::RE re("([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})", pcrecpp::RE_Options(PCRE_CASELESS)); - string value; - re.PartialMatch(m_startParser.vPlaylistItems[0].file, &value); - m_sessionCookie = value; - } - } catch (Poco::Exception &exc) { - esyslog("[plex] %s %s", __FUNCTION__, exc.displayText().c_str()); - res = false; - } - return res; -} - -int cHlsSegmentLoader::EstimateSegmentSize() -{ - if(&m_startParser.vPlaylistItems[0] == NULL) { - esyslog("[plex]%s first element NULL", __FUNCTION__); - } - double bandw = m_startParser.vPlaylistItems[0].bandwidth / 8.0 / 1000.0 / 1000.0; - - int len = m_indexParser.TargetDuration; - double estSize = (bandw) * len; - estSize = std::max(estSize, 1.0); - // default - if(estSize <= 1) { - estSize = 32; - } - return ceil(estSize); -} - -bool cHlsSegmentLoader::LoadSegment(std::string segmentUri) -{ - try { - Poco::Net::HTTPRequest segmentRequest(Poco::Net::HTTPRequest::HTTP_GET, segmentUri); - AddHeader(segmentRequest); - m_pClientSession->sendRequest(segmentRequest); - } catch (Poco::Exception&) { - esyslog("[plex] %s; %s failed.", __FUNCTION__, segmentUri.c_str()); - return false; - } - Poco::Net::HTTPResponse segmentResponse; - std::istream& segmentFile = m_pClientSession->receiveResponse(segmentResponse); - - if(segmentResponse.getStatus() != 200) { - // error - esyslog("[plex] %s; %s failed.", __FUNCTION__, segmentUri.c_str()); - return false; - } - - if(segmentResponse.getContentLength() <= TS_SIZE) { - // Empty segment - dsyslog("[plex] %s: %s <= 188 byte.", __FUNCTION__, segmentUri.c_str()); - return true; - } - - dsyslog("[plex] %s: %s successfully.", __FUNCTION__, segmentUri.c_str()); - // copy response - segmentFile.read(reinterpret_cast<char*>(m_pBuffer), BUFFERSIZE); - std::streamsize n = segmentFile.gcount(); - while(n > 0) { - if(m_pRingbuffer->Free() >= n) { - m_pRingbuffer->Put(m_pBuffer, n); - - segmentFile.read(reinterpret_cast<char*>(m_pBuffer), BUFFERSIZE); - n = segmentFile.gcount(); - m_bufferFilled = true; - } - else { - cCondWait::SleepMs(1); - } - if(m_newList) { - break; - } - } - return true; -} - -int cHlsSegmentLoader::GetSegmentSize(int segmentIndex) -{ - //dsyslog("[plex]%s Segment %d", __FUNCTION__, segmentIndex); - if(m_indexParser.vPlaylistItems[segmentIndex].size >= TS_SIZE) { - return m_indexParser.vPlaylistItems[segmentIndex].size; - } - try { - Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_HEAD, GetSegmentUri(segmentIndex)); - AddHeader(req); - m_pClientSession->sendRequest(req); - Poco::Net::HTTPResponse reqResponse; - m_pClientSession->receiveResponse(reqResponse); - return m_indexParser.vPlaylistItems[segmentIndex].size = reqResponse.getContentLength(); - } catch(Poco::IOException& exc) { - esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str()); - return 0; - } -} - -std::string cHlsSegmentLoader::GetSegmentUri(int segmentIndex) const -{ - return m_segmentUriPart + m_indexParser.vPlaylistItems[segmentIndex].file; -} - -void cHlsSegmentLoader::CloseConnection(void) -{ - if(m_pClientSession) - m_pClientSession->abort(); - - delete m_pClientSession; - m_pClientSession = NULL; -} - -bool cHlsSegmentLoader::ConnectToServer(void) -{ - dsyslog("[plex]%s", __FUNCTION__); - if(!m_pClientSession) { - if(m_startUri.getScheme().find("https") != std::string::npos) { - m_pClientSession = new Poco::Net::HTTPSClientSession(m_startUri.getHost(), m_startUri.getPort()); - } - else { - m_pClientSession = new Poco::Net::HTTPClientSession(m_startUri.getHost(), m_startUri.getPort()); - } - } - - return m_pClientSession->connected(); -} - -bool cHlsSegmentLoader::DoLoad(void) -{ - LOCK_THREAD; - bool result = true; - bool recover = false; - if(m_lastLoadedSegment < m_indexParser.vPlaylistItems.size()) { - - std::string segmentUri = GetSegmentUri(m_lastLoadedSegment); - if((result = LoadSegment(segmentUri))) { - m_lastLoadedSegment++; - } else { - // transcoder may be died, plex bug, restart transcode session - esyslog("[plex] %s 404, Transcoder died, see logfile from PMS", __FUNCTION__); - recover = true; - std::string stopUri = "/video/:/transcode/universal/stop?session=" + m_sessionCookie; - try { - - bool ok; - auto cSession = m_pVideo->m_pServer->MakeRequest(ok, stopUri); - int tmp = m_lastLoadedSegment; - int tmp2 = m_lastSegmentSize; - CloseConnection(); - LoadLists(); - m_lastLoadedSegment = tmp; - m_lastSegmentSize = tmp2; - } catch (Poco::Exception&) { - return false; - } - } - - m_bufferFilled = result; - } else { - result = false; - } - return recover || result; -} - -bool cHlsSegmentLoader::BufferFilled(void) -{ - return m_bufferFilled; -} - -bool cHlsSegmentLoader::StopLoader(void) -{ - dsyslog("[plex]%s", __FUNCTION__); - try { - std::string stopUri = "/video/:/transcode/universal/stop?session=" + m_sessionCookie; - - bool ok; - auto cSession = m_pVideo->m_pServer->MakeRequest(ok, stopUri); - - Cancel(); - - return ok; - } catch(Poco::Exception& exc) { - esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str()); - return false; - } -} -void cHlsSegmentLoader::AddHeader(Poco::Net::HTTPRequest& req) -{ - req.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); +cHlsSegmentLoader::cHlsSegmentLoader(std::string startm3u8, plexclient::cVideo *pVideo) { + m_pVideo = pVideo; + m_newList = false; + m_bufferFilled = false; + m_lastLoadedSegment = 0; + m_segmentsToBuffer = 2; + m_streamlenght = 0; + m_lastSegmentSize = 0; + m_pBuffer = new uchar[BUFFERSIZE]; + + // Initialize members + m_pClientSession = NULL; + + m_ringBufferSize = MEGABYTE(1); + m_pRingbuffer = NULL; + + m_startUri = Poco::URI(startm3u8); + m_startParser = cM3u8Parser(); + m_indexParser = cM3u8Parser(); +} + +cHlsSegmentLoader::~cHlsSegmentLoader() { + // Stop Thread + Cancel(0); + + delete m_pClientSession; + delete[] m_pBuffer; + delete m_pRingbuffer; +} + +void cHlsSegmentLoader::SkipEmptySegments(int segmentDuration) { + pcrecpp::RE re("&offset=(\\d+)", pcrecpp::RE_Options(PCRE_CASELESS)); + int value; + re.PartialMatch(m_startUri.getQuery(), &value); + if (value > segmentDuration) { + m_lastLoadedSegment = (value / segmentDuration) - 1; + } +} + +bool cHlsSegmentLoader::LoadM3u8(std::string uri) { + //LOCK_THREAD; + m_startUri = Poco::URI(uri); + return (m_newList = true); +} + +void cHlsSegmentLoader::Action(void) { + if (!LoadLists()) return; + + m_ringBufferSize = MEGABYTE(Config::GetInstance().BufferSize); + + isyslog("[plex]%s Create Ringbuffer %d MB", __FUNCTION__, Config::GetInstance().BufferSize); + + m_pRingbuffer = new cRingBufferLinear(m_ringBufferSize, 2 * TS_SIZE); + + while (Running()) { + if (m_newList) { + hlsMutex.Lock(); + m_bufferFilled = false; + m_lastLoadedSegment = 0; + LoadLists(); + m_newList = false; + m_pRingbuffer->Clear(); + isyslog("[plex] Ringbuffer Cleared, loading new segments"); + hlsMutex.Unlock(); + } + int count = 0; + m_pRingbuffer->Get(count); + if (!DoLoad() && count < TS_SIZE) { + isyslog("[plex] No further segments to load and buffer empty, end of stream!"); + Cancel(); + + } + cCondWait::SleepMs(3); + } + StopLoader(); +} + +bool cHlsSegmentLoader::LoadLists(void) { + if (LoadStartList()) { + if (false == LoadIndexList()) { + esyslog("[plex]LoadIndexList failed!"); + return false; + } + } else { + esyslog("[plex]LoadStartList failed!"); + return false; + } + return true; +} + +bool cHlsSegmentLoader::LoadIndexList(void) { + bool res = false; + try { + if (m_startParser.MasterPlaylist && m_startParser.vPlaylistItems.size() > 0) { + // Todo: make it universal, might only work for Plexmediaserver + ConnectToServer(); + + std::string startUri = m_startUri.toString(); + startUri = startUri.substr(0, startUri.find_last_of("/") + 1); + + Poco::URI indexUri(startUri + m_startParser.vPlaylistItems[0].file); + + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, indexUri.getPath()); + AddHeader(request); + // same server + m_pClientSession->sendRequest(request); + + Poco::Net::HTTPResponse responseStart; + std::istream &indexFile = m_pClientSession->receiveResponse(responseStart); + + if (responseStart.getStatus() != 200) { + esyslog("[plex]%s Response Not Valid", __FUNCTION__); + Poco::StreamCopier::copyStream(indexFile, std::cout); + return res; + } + m_indexParser = cM3u8Parser(); + res = m_indexParser.Parse(indexFile); + + if (res) { + // Segment URI is relative to index.m3u8 + std::string path = indexUri.getPath(); + m_segmentUriPart = path.substr(0, path.find_last_of("/") + 1); + } + if (m_indexParser.TargetDuration > 3) { + m_segmentsToBuffer = 2; + } else { + m_segmentsToBuffer = 3; + } + + SkipEmptySegments(m_indexParser.TargetDuration); + m_lastSegmentSize = 0; + + // Get stream lenght + m_streamlenght = 0; + for (unsigned int i = 0; i < m_indexParser.vPlaylistItems.size(); i++) { + m_streamlenght += m_indexParser.vPlaylistItems[i].length; + } + } + + } catch (Poco::Exception &exc) { + esyslog("[plex] %s %s", __FUNCTION__, exc.displayText().c_str()); + res = false; + } + return res; +} + +bool cHlsSegmentLoader::LoadStartList(void) { + bool res = false; + ConnectToServer(); + try { + dsyslog("[plex]%s %s", __FUNCTION__, m_startUri.toString().c_str()); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, m_startUri.getPathAndQuery()); + AddHeader(request); + m_pClientSession->sendRequest(request); + + Poco::Net::HTTPResponse responseStart; + std::istream &startFile = m_pClientSession->receiveResponse(responseStart); + + if (responseStart.getStatus() != 200) { + esyslog("[plex]%s Response Not Valid", __FUNCTION__); + Poco::StreamCopier::copyStream(startFile, std::cout); + return res; + } + + m_startParser = cM3u8Parser(); + res = m_startParser.Parse(startFile); + if (res) { + // Get GUID + pcrecpp::RE re("([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})", + pcrecpp::RE_Options(PCRE_CASELESS)); + string value; + re.PartialMatch(m_startParser.vPlaylistItems[0].file, &value); + m_sessionCookie = value; + } + } catch (Poco::Exception &exc) { + esyslog("[plex] %s %s", __FUNCTION__, exc.displayText().c_str()); + res = false; + } + return res; +} + +int cHlsSegmentLoader::EstimateSegmentSize() { + if (&m_startParser.vPlaylistItems[0] == NULL) { + esyslog("[plex]%s first element NULL", __FUNCTION__); + } + double bandw = m_startParser.vPlaylistItems[0].bandwidth / 8.0 / 1000.0 / 1000.0; + + int len = m_indexParser.TargetDuration; + double estSize = (bandw) * len; + estSize = std::max(estSize, 1.0); + // default + if (estSize <= 1) { + estSize = 32; + } + return ceil(estSize); +} + +bool cHlsSegmentLoader::LoadSegment(std::string segmentUri) { + try { + Poco::Net::HTTPRequest segmentRequest(Poco::Net::HTTPRequest::HTTP_GET, segmentUri); + AddHeader(segmentRequest); + m_pClientSession->sendRequest(segmentRequest); + } catch (Poco::Exception &) { + esyslog("[plex] %s; %s failed.", __FUNCTION__, segmentUri.c_str()); + return false; + } + Poco::Net::HTTPResponse segmentResponse; + std::istream &segmentFile = m_pClientSession->receiveResponse(segmentResponse); + + if (segmentResponse.getStatus() != 200) { + // error + esyslog("[plex] %s; %s failed.", __FUNCTION__, segmentUri.c_str()); + return false; + } + + if (segmentResponse.getContentLength() <= TS_SIZE) { + // Empty segment + dsyslog("[plex] %s: %s <= 188 byte.", __FUNCTION__, segmentUri.c_str()); + return true; + } + + dsyslog("[plex] %s: %s successfully.", __FUNCTION__, segmentUri.c_str()); + // copy response + segmentFile.read(reinterpret_cast<char *>(m_pBuffer), BUFFERSIZE); + std::streamsize n = segmentFile.gcount(); + while (n > 0) { + if (m_pRingbuffer->Free() >= n) { + m_pRingbuffer->Put(m_pBuffer, n); + + segmentFile.read(reinterpret_cast<char *>(m_pBuffer), BUFFERSIZE); + n = segmentFile.gcount(); + m_bufferFilled = true; + } + else { + cCondWait::SleepMs(1); + } + if (m_newList) { + break; + } + } + return true; +} + +int cHlsSegmentLoader::GetSegmentSize(int segmentIndex) { + //dsyslog("[plex]%s Segment %d", __FUNCTION__, segmentIndex); + if (m_indexParser.vPlaylistItems[segmentIndex].size >= TS_SIZE) { + return m_indexParser.vPlaylistItems[segmentIndex].size; + } + try { + Poco::Net::HTTPRequest req(Poco::Net::HTTPRequest::HTTP_HEAD, GetSegmentUri(segmentIndex)); + AddHeader(req); + m_pClientSession->sendRequest(req); + Poco::Net::HTTPResponse reqResponse; + m_pClientSession->receiveResponse(reqResponse); + return m_indexParser.vPlaylistItems[segmentIndex].size = reqResponse.getContentLength(); + } catch (Poco::IOException &exc) { + esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str()); + return 0; + } +} + +std::string cHlsSegmentLoader::GetSegmentUri(int segmentIndex) const { + return m_segmentUriPart + m_indexParser.vPlaylistItems[segmentIndex].file; +} + +void cHlsSegmentLoader::CloseConnection(void) { + if (m_pClientSession) + m_pClientSession->abort(); + + delete m_pClientSession; + m_pClientSession = NULL; +} + +bool cHlsSegmentLoader::ConnectToServer(void) { + dsyslog("[plex]%s", __FUNCTION__); + if (!m_pClientSession) { + if (m_startUri.getScheme().find("https") != std::string::npos) { + m_pClientSession = new Poco::Net::HTTPSClientSession(m_startUri.getHost(), m_startUri.getPort()); + } + else { + m_pClientSession = new Poco::Net::HTTPClientSession(m_startUri.getHost(), m_startUri.getPort()); + } + } + + return m_pClientSession->connected(); +} + +bool cHlsSegmentLoader::DoLoad(void) { + LOCK_THREAD; + bool result = true; + bool recover = false; + if (m_lastLoadedSegment < m_indexParser.vPlaylistItems.size()) { + + std::string segmentUri = GetSegmentUri(m_lastLoadedSegment); + if ((result = LoadSegment(segmentUri))) { + m_lastLoadedSegment++; + } else { + // transcoder may be died, plex bug, restart transcode session + esyslog("[plex] %s 404, Transcoder died, see logfile from PMS", __FUNCTION__); + recover = true; + std::string stopUri = "/video/:/transcode/universal/stop?session=" + m_sessionCookie; + try { + + bool ok; + auto cSession = m_pVideo->m_pServer->MakeRequest(ok, stopUri); + int tmp = m_lastLoadedSegment; + int tmp2 = m_lastSegmentSize; + CloseConnection(); + LoadLists(); + m_lastLoadedSegment = tmp; + m_lastSegmentSize = tmp2; + } catch (Poco::Exception &) { + return false; + } + } + + m_bufferFilled = result; + } else { + result = false; + } + return recover || result; +} + +bool cHlsSegmentLoader::BufferFilled(void) { + return m_bufferFilled; +} + +bool cHlsSegmentLoader::StopLoader(void) { + dsyslog("[plex]%s", __FUNCTION__); + try { + std::string stopUri = "/video/:/transcode/universal/stop?session=" + m_sessionCookie; + + bool ok; + auto cSession = m_pVideo->m_pServer->MakeRequest(ok, stopUri); + + Cancel(); + + return ok; + } catch (Poco::Exception &exc) { + esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str()); + return false; + } +} + +void cHlsSegmentLoader::AddHeader(Poco::Net::HTTPRequest &req) { + req.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID()); // req.add("X-Plex-Device", "PC"); - req.add("X-Plex-Model", "Linux"); - if(Config::GetInstance().UseCustomTranscodeProfile) { - req.add("X-Plex-Device", "VDR Plex Plugin"); - } else { - req.add("X-Plex-Device", "Plex Home Theater"); - //req.add("X-Plex-Device", "tvOS"); - } - - if(Config::GetInstance().UsePlexAccount && !m_pVideo->m_pServer->GetAuthToken().empty()) { - // Add PlexToken to Header - req.add("X-Plex-Token", m_pVideo->m_pServer->GetAuthToken()); - } -} - -bool cHlsSegmentLoader::Active(void) -{ - return Running(); -} - -void cHlsSegmentLoader::Ping(void) -{ - dsyslog("[plex]%s", __FUNCTION__); - try { - std::string uri = "/video/:/transcode/universal/ping?session=" + Config::GetInstance().GetUUID(); - - bool ok; - auto cSession = m_pVideo->m_pServer->MakeRequest(ok, uri); - - } catch(Poco::Exception& exc) { - esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str()); - } -} - -void cHlsSegmentLoader::ResizeRingbuffer(int newsize) -{ - hlsMutex.Lock(); - isyslog("[plex] %s, Oldsize: %d, Newsize: %d", __FUNCTION__, m_ringBufferSize, newsize); - //Create new Ringbuffer - cRingBufferLinear* newBuffer = new cRingBufferLinear(newsize, TS_SIZE); - // Copy old data - int count = 0; - uchar* pData = m_pRingbuffer->Get(count); - newBuffer->Put(pData, count); - // delete old buffer - delete m_pRingbuffer; - m_pRingbuffer = NULL; - // assing new buffer - m_pRingbuffer = newBuffer; - m_ringBufferSize = newsize; - hlsMutex.Unlock(); -} - -int cHlsSegmentLoader::GetStreamLenght() -{ - return m_streamlenght; + req.add("X-Plex-Model", "Linux"); + if (Config::GetInstance().UseCustomTranscodeProfile) { + req.add("X-Plex-Device", "VDR Plex Plugin"); + } else { + req.add("X-Plex-Device", "Plex Home Theater"); + //req.add("X-Plex-Device", "tvOS"); + } + + if (Config::GetInstance().UsePlexAccount && !m_pVideo->m_pServer->GetAuthToken().empty()) { + // Add PlexToken to Header + req.add("X-Plex-Token", m_pVideo->m_pServer->GetAuthToken()); + } +} + +bool cHlsSegmentLoader::Active(void) { + return Running(); +} + +void cHlsSegmentLoader::Ping(void) { + dsyslog("[plex]%s", __FUNCTION__); + try { + std::string uri = "/video/:/transcode/universal/ping?session=" + Config::GetInstance().GetUUID(); + + bool ok; + auto cSession = m_pVideo->m_pServer->MakeRequest(ok, uri); + + } catch (Poco::Exception &exc) { + esyslog("[plex]%s %s ", __FUNCTION__, exc.displayText().c_str()); + } +} + +void cHlsSegmentLoader::ResizeRingbuffer(int newsize) { + hlsMutex.Lock(); + isyslog("[plex] %s, Oldsize: %d, Newsize: %d", __FUNCTION__, m_ringBufferSize, newsize); + //Create new Ringbuffer + cRingBufferLinear *newBuffer = new cRingBufferLinear(newsize, TS_SIZE); + // Copy old data + int count = 0; + uchar *pData = m_pRingbuffer->Get(count); + newBuffer->Put(pData, count); + // delete old buffer + delete m_pRingbuffer; + m_pRingbuffer = NULL; + // assing new buffer + m_pRingbuffer = newBuffer; + m_ringBufferSize = newsize; + hlsMutex.Unlock(); +} + +int cHlsSegmentLoader::GetStreamLenght() { + return m_streamlenght; } //--- cHlsPlayer -cHlsPlayer::cHlsPlayer(std::string startm3u8, plexclient::cVideo Video, int offset) -{ - dsyslog("[plex]: '%s'", __FUNCTION__); - m_Video = Video; - m_timeOffset = offset; - m_jumpOffset = 0; - m_tTimeSum = 0; - m_doJump = false; - m_isBuffering = false; - AudioIndexOffset = 1000; // Just a magic number - m_tTimer.Set(1); - m_pSegmentLoader = new cHlsSegmentLoader(startm3u8, &m_Video); - - m_pDebugFile = NULL; - //m_pDebugFile = new std::ofstream(); - //m_pDebugFile->open("debug.ts", std::ios::out); -} - -cHlsPlayer::~cHlsPlayer() -{ - dsyslog("[plex]: '%s'", __FUNCTION__); - Cancel(); - if(m_pDebugFile) m_pDebugFile->close(); - delete m_pDebugFile; - m_pDebugFile = NULL; - - delete m_pSegmentLoader; - m_pSegmentLoader = NULL; - Detach(); -} - -void cHlsPlayer::SetAudioAndSubtitleTracks(void) -{ - //DeviceClrAvailableTracks(); - DeviceSetAvailableTrack(ttDolby, 0, 0, "Current"); - if(m_Video.m_Media.m_vStreams.size() > 0) { - std::vector<plexclient::Stream> streams = m_Video.m_Media.m_vStreams; - for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { - plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::StreamType::sAUDIO) { - DeviceSetAvailableTrack(ttDolby, pStream->m_iIndex, pStream->m_iIndex + AudioIndexOffset, pStream->m_sLanguage.c_str(), pStream->m_sCodec.c_str()); - } - } - } -} - - -void cHlsPlayer::Action(void) -{ - // Start SegmentLoader - m_pSegmentLoader->Start(); - - m_bFirstPlay = true; - - while (Running()) { - if(m_doJump && m_pSegmentLoader && m_pSegmentLoader->BufferFilled()) { - LOCK_THREAD; - - DeviceFreeze(); - m_doJump = false; - m_bFirstPlay = true; - std::string uri = plexclient::Plexservice::GetUniversalTranscodeUrl(&m_Video, m_jumpOffset); - m_pSegmentLoader->LoadM3u8(uri); - m_timeOffset = m_jumpOffset; - DeviceClear(); - DevicePlay(); - playMode = pmPlay; - } else if(m_pSegmentLoader && m_pSegmentLoader->BufferFilled()) { - DoPlay(); - if(m_bFirstPlay) { - SetAudioAndSubtitleTracks(); - ResetPlayedSeconds(); - playMode = pmPlay; - m_bFirstPlay = false; - } - CountPlayedSeconds(); - } else { - // Pause - cCondWait::SleepMs(3); - } - // statusupdates to pms every 60s - if(m_pSegmentLoader && m_tTimer.TimedOut()) { - if(playMode == pmPause) { - m_pSegmentLoader->Ping(); - } - ReportProgress(); - m_tTimer.Set(60000); - } - } - // set as watched if >= 90% - int t = m_Video.m_Media.m_lDuration / 1000 * 0.9; - if( GetPlayedSeconds() >= t) { - SetWatched(); - } - DeviceClear(); -} - -bool cHlsPlayer::DoPlay(void) -{ - bool res = false; - cPoller Poller; - if(DevicePoll(Poller, 10)) { - hlsMutex.Lock(); +cHlsPlayer::cHlsPlayer(std::string startm3u8, plexclient::cVideo Video, int offset) { + dsyslog("[plex]: '%s'", __FUNCTION__); + m_Video = Video; + m_timeOffset = offset; + m_jumpOffset = 0; + m_tTimeSum = 0; + m_doJump = false; + m_isBuffering = false; + AudioIndexOffset = 1000; // Just a magic number + m_tTimer.Set(1); + m_pSegmentLoader = new cHlsSegmentLoader(startm3u8, &m_Video); + + m_pDebugFile = NULL; + //m_pDebugFile = new std::ofstream(); + //m_pDebugFile->open("debug.ts", std::ios::out); +} + +cHlsPlayer::~cHlsPlayer() { + dsyslog("[plex]: '%s'", __FUNCTION__); + Cancel(); + if (m_pDebugFile) m_pDebugFile->close(); + delete m_pDebugFile; + m_pDebugFile = NULL; + + delete m_pSegmentLoader; + m_pSegmentLoader = NULL; + Detach(); +} + +void cHlsPlayer::SetAudioAndSubtitleTracks(void) { + //DeviceClrAvailableTracks(); + DeviceSetAvailableTrack(ttDolby, 0, 0, "Current"); + if (m_Video.m_Media.m_vStreams.size() > 0) { + std::vector<plexclient::Stream> streams = m_Video.m_Media.m_vStreams; + for (std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { + plexclient::Stream *pStream = &(*it); + if (pStream->m_eStreamType == plexclient::StreamType::sAUDIO) { + DeviceSetAvailableTrack(ttDolby, pStream->m_iIndex, pStream->m_iIndex + AudioIndexOffset, + pStream->m_sLanguage.c_str(), pStream->m_sCodec.c_str()); + } + } + } +} + + +void cHlsPlayer::Action(void) { + // Start SegmentLoader + m_pSegmentLoader->Start(); + + m_bFirstPlay = true; + + while (Running()) { + if (m_doJump && m_pSegmentLoader && m_pSegmentLoader->BufferFilled()) { + LOCK_THREAD; + + DeviceFreeze(); + m_doJump = false; + m_bFirstPlay = true; + std::string uri = plexclient::Plexservice::GetUniversalTranscodeUrl(&m_Video, m_jumpOffset); + m_pSegmentLoader->LoadM3u8(uri); + m_timeOffset = m_jumpOffset; + DeviceClear(); + DevicePlay(); + playMode = pmPlay; + } else if (m_pSegmentLoader && m_pSegmentLoader->BufferFilled()) { + DoPlay(); + if (m_bFirstPlay) { + SetAudioAndSubtitleTracks(); + ResetPlayedSeconds(); + playMode = pmPlay; + m_bFirstPlay = false; + } + CountPlayedSeconds(); + } else { + // Pause + cCondWait::SleepMs(3); + } + // statusupdates to pms every 60s + if (m_pSegmentLoader && m_tTimer.TimedOut()) { + if (playMode == pmPause) { + m_pSegmentLoader->Ping(); + } + ReportProgress(); + m_tTimer.Set(60000); + } + } + // set as watched if >= 90% + int t = m_Video.m_Media.m_lDuration / 1000 * 0.9; + if (GetPlayedSeconds() >= t) { + SetWatched(); + } + DeviceClear(); +} + +bool cHlsPlayer::DoPlay(void) { + bool res = false; + cPoller Poller; + if (DevicePoll(Poller, 10)) { + hlsMutex.Lock(); // Handle running out of packets. Buffer-> Play-> Pause-> Buffer-> Play - for(int i = 0; i < 10; i++) { - // Get a pointer to start of the data and the number of avaliable bytes - int bytesAvaliable = 0; - uchar* toPlay = m_pSegmentLoader->m_pRingbuffer->Get(bytesAvaliable); - if(bytesAvaliable >= TS_SIZE) { - int playedBytes = PlayTs(toPlay, TS_SIZE, false); - // save stream to disk to debug data - if(m_pDebugFile) { - m_pDebugFile-> write((char*)toPlay, playedBytes); - } - - m_pSegmentLoader->m_pRingbuffer->Del(playedBytes); - res = true; - } else { - // Pause & Buffer - break; - } - } - hlsMutex.Unlock(); - } - return res; -} - -void cHlsPlayer::Activate(bool On) -{ - if(On) { - Start(); - } else { - Cancel(1); - } -} - -bool cHlsPlayer::GetIndex(int& Current, int& Total, bool SnapToIFrame __attribute__((unused))) -{ - if(m_Video.m_Media.m_lDuration > 0) { - Total = m_Video.m_Media.m_lDuration / 1000 * FramesPerSecond(); // milliseconds - } else { - Total = m_pSegmentLoader->GetStreamLenght() * FramesPerSecond(); - } - Current = GetPlayedSeconds() * FramesPerSecond(); - return true; -} - -bool cHlsPlayer::GetReplayMode(bool& Play, bool& Forward, int& Speed) -{ - Play = (playMode == pmPlay); - Forward = true; - Speed = -1; - return true; -} - -void cHlsPlayer::Pause(void) -{ - LOCK_THREAD; - dsyslog("[plex]%s", __FUNCTION__); - if (playMode == pmPause) { - Play(); - } else { - DeviceFreeze(); - playMode = pmPause; - } -} - -void cHlsPlayer::Play(void) -{ - LOCK_THREAD; - dsyslog("[plex]%s", __FUNCTION__); - if (playMode != pmPlay) { - DevicePlay(); - playMode = pmPlay; - } -} - -bool cHlsPlayer::Active(void) -{ - return Running() && m_pSegmentLoader && m_pSegmentLoader->Active(); -} - -void cHlsPlayer::Stop(void) -{ - LOCK_THREAD; - dsyslog("[plex]%s", __FUNCTION__); - ReportProgress(true); - if (m_pSegmentLoader) - m_pSegmentLoader->StopLoader(); - Cancel(1); -} - -double cHlsPlayer::FramesPerSecond(void) -{ - return m_Video.m_Media.m_VideoFrameRate == "24p" ? 24 : DEFAULTFRAMESPERSECOND; -} - -void cHlsPlayer::JumpRelative(int seconds) -{ - JumpTo(GetPlayedSeconds() + seconds); -} - -void cHlsPlayer::JumpTo(int seconds) -{ - LOCK_THREAD; - dsyslog("[plex]%s %d", __FUNCTION__, seconds); - if(seconds < 0) seconds = 0; - m_jumpOffset = seconds; - m_doJump = true; -} - -void cHlsPlayer::SetAudioTrack(eTrackType Type __attribute__((unused)), const tTrackId* TrackId) -{ - LOCK_THREAD; - dsyslog("[plex]%s %d %s", __FUNCTION__, TrackId->id, TrackId->language); - // Check if stream availiable - int streamId = 0; - if(m_Video.m_Media.m_vStreams.size() > 0) { - std::vector<plexclient::Stream> streams = m_Video.m_Media.m_vStreams; - for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { - plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::StreamType::sAUDIO && pStream->m_iIndex + AudioIndexOffset == TrackId->id) { - streamId = pStream->m_iID; - break; - } - } - } - // Then do the request - if(streamId > 0) { - std::string uri = "/library/parts/" + std::string(itoa(m_Video.m_Media.m_iPartId)) + "?audioStreamID=" + std::string(itoa(streamId)); - - bool ok; - auto cSession = m_Video.m_pServer->MakeRequest(ok, uri); - if(ok) { - DeviceSetCurrentAudioTrack(eTrackType(ttDolby + 0)); // hacky - DeviceSetAvailableTrack(ttDolby, 0, 0, TrackId->language); - JumpRelative(0); // Reload Stream to get new Audio - dsyslog("[plex]: Set AudioStream: %d\n", TrackId->id); - } - } -} - -int cHlsPlayer::GetPlayedSeconds(void) -{ - return m_timeOffset + (m_tTimeSum / 1000); -} - -void cHlsPlayer::CountPlayedSeconds(void) -{ - if (playMode == pmPlay) { - unsigned long long tTmp = cTimeMs::Now(); - m_tTimeSum += (tTmp - m_tLastTime); - m_tLastTime = tTmp; - } else { - m_tLastTime = cTimeMs::Now(); - } -} - -void cHlsPlayer::ResetPlayedSeconds(void) -{ - m_tTimeSum = 0; - m_tLastTime = cTimeMs::Now(); -} - -void cHlsPlayer::ReportProgress(bool stopped) -{ - std::string state; - if(stopped) { - state = "stopped"; - } else if (playMode == pmPlay) { - state = "playing"; - } else { - state = "paused"; - } - - try { - std::string uri = "/:/progress?key=" + std::string(itoa(m_Video.m_iRatingKey)) + "&identifier=com.plexapp.plugins.library&time=" + std::string(itoa(GetPlayedSeconds()*1000)) + "&state=" + state; - - bool ok; - auto cSession = m_Video.m_pServer->MakeRequest(ok, uri); - - if(ok) { - dsyslog("[plex] %s", __FUNCTION__); - } - } catch (Poco::Exception&) {} - -} - -void cHlsPlayer::SetWatched(void) -{ - std::string uri = "/:/scrobble?key=" + std::string(itoa(m_Video.m_iRatingKey)) + "&identifier=com.plexapp.plugins.library"; - - bool ok; - auto cSession = m_Video.m_pServer->MakeRequest(ok, uri); - - if(ok) { - dsyslog("[plex] %s", __FUNCTION__); - } + for (int i = 0; i < 10; i++) { + // Get a pointer to start of the data and the number of avaliable bytes + int bytesAvaliable = 0; + uchar *toPlay = m_pSegmentLoader->m_pRingbuffer->Get(bytesAvaliable); + if (bytesAvaliable >= TS_SIZE) { + int playedBytes = PlayTs(toPlay, TS_SIZE, false); + // save stream to disk to debug data + if (m_pDebugFile) { + m_pDebugFile->write((char *) toPlay, playedBytes); + } + + m_pSegmentLoader->m_pRingbuffer->Del(playedBytes); + res = true; + } else { + // Pause & Buffer + break; + } + } + hlsMutex.Unlock(); + } + return res; +} + +void cHlsPlayer::Activate(bool On) { + if (On) { + Start(); + } else { + Cancel(1); + } +} + +bool cHlsPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame __attribute__((unused))) { + if (m_Video.m_Media.m_lDuration > 0) { + Total = m_Video.m_Media.m_lDuration / 1000 * FramesPerSecond(); // milliseconds + } else { + Total = m_pSegmentLoader->GetStreamLenght() * FramesPerSecond(); + } + Current = GetPlayedSeconds() * FramesPerSecond(); + return true; +} + +bool cHlsPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) { + Play = (playMode == pmPlay); + Forward = true; + Speed = -1; + return true; +} + +void cHlsPlayer::Pause(void) { + LOCK_THREAD; + dsyslog("[plex]%s", __FUNCTION__); + if (playMode == pmPause) { + Play(); + } else { + DeviceFreeze(); + playMode = pmPause; + } +} + +void cHlsPlayer::Play(void) { + LOCK_THREAD; + dsyslog("[plex]%s", __FUNCTION__); + if (playMode != pmPlay) { + DevicePlay(); + playMode = pmPlay; + } +} + +bool cHlsPlayer::Active(void) { + return Running() && m_pSegmentLoader && m_pSegmentLoader->Active(); +} + +void cHlsPlayer::Stop(void) { + LOCK_THREAD; + dsyslog("[plex]%s", __FUNCTION__); + ReportProgress(true); + if (m_pSegmentLoader) + m_pSegmentLoader->StopLoader(); + Cancel(1); +} + +double cHlsPlayer::FramesPerSecond(void) { + return m_Video.m_Media.m_VideoFrameRate == "24p" ? 24 : DEFAULTFRAMESPERSECOND; +} + +void cHlsPlayer::JumpRelative(int seconds) { + JumpTo(GetPlayedSeconds() + seconds); +} + +void cHlsPlayer::JumpTo(int seconds) { + LOCK_THREAD; + dsyslog("[plex]%s %d", __FUNCTION__, seconds); + if (seconds < 0) seconds = 0; + m_jumpOffset = seconds; + m_doJump = true; +} + +void cHlsPlayer::SetAudioTrack(eTrackType Type __attribute__((unused)), const tTrackId *TrackId) { + LOCK_THREAD; + dsyslog("[plex]%s %d %s", __FUNCTION__, TrackId->id, TrackId->language); + // Check if stream availiable + int streamId = 0; + if (m_Video.m_Media.m_vStreams.size() > 0) { + std::vector<plexclient::Stream> streams = m_Video.m_Media.m_vStreams; + for (std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { + plexclient::Stream *pStream = &(*it); + if (pStream->m_eStreamType == plexclient::StreamType::sAUDIO && + pStream->m_iIndex + AudioIndexOffset == TrackId->id) { + streamId = pStream->m_iID; + break; + } + } + } + // Then do the request + if (streamId > 0) { + std::string uri = "/library/parts/" + std::string(itoa(m_Video.m_Media.m_iPartId)) + "?audioStreamID=" + + std::string(itoa(streamId)); + + bool ok; + auto cSession = m_Video.m_pServer->MakeRequest(ok, uri); + if (ok) { + DeviceSetCurrentAudioTrack(eTrackType(ttDolby + 0)); // hacky + DeviceSetAvailableTrack(ttDolby, 0, 0, TrackId->language); + JumpRelative(0); // Reload Stream to get new Audio + dsyslog("[plex]: Set AudioStream: %d\n", TrackId->id); + } + } +} + +int cHlsPlayer::GetPlayedSeconds(void) { + return m_timeOffset + (m_tTimeSum / 1000); +} + +void cHlsPlayer::CountPlayedSeconds(void) { + if (playMode == pmPlay) { + unsigned long long tTmp = cTimeMs::Now(); + m_tTimeSum += (tTmp - m_tLastTime); + m_tLastTime = tTmp; + } else { + m_tLastTime = cTimeMs::Now(); + } +} + +void cHlsPlayer::ResetPlayedSeconds(void) { + m_tTimeSum = 0; + m_tLastTime = cTimeMs::Now(); +} + +void cHlsPlayer::ReportProgress(bool stopped) { + std::string state; + if (stopped) { + state = "stopped"; + } else if (playMode == pmPlay) { + state = "playing"; + } else { + state = "paused"; + } + + try { + std::string uri = "/:/progress?key=" + std::string(itoa(m_Video.m_iRatingKey)) + + "&identifier=com.plexapp.plugins.library&time=" + + std::string(itoa(GetPlayedSeconds() * 1000)) + "&state=" + state; + + bool ok; + auto cSession = m_Video.m_pServer->MakeRequest(ok, uri); + + if (ok) { + dsyslog("[plex] %s", __FUNCTION__); + } + } catch (Poco::Exception &) { } + +} + +void cHlsPlayer::SetWatched(void) { + std::string uri = + "/:/scrobble?key=" + std::string(itoa(m_Video.m_iRatingKey)) + "&identifier=com.plexapp.plugins.library"; + + bool ok; + auto cSession = m_Video.m_pServer->MakeRequest(ok, uri); + + if (ok) { + dsyslog("[plex] %s", __FUNCTION__); + } } diff --git a/hlsPlayer.h b/hlsPlayer.h index 21e6651..3918d4f 100644 --- a/hlsPlayer.h +++ b/hlsPlayer.h @@ -19,114 +19,150 @@ #include "PVideo.h" #include "Media.h" -class cHlsSegmentLoader : public cThread -{ +class cHlsSegmentLoader : public cThread { private: - int m_ringBufferSize; - unsigned int m_segmentsToBuffer; - unsigned int m_lastLoadedSegment; - int m_lastSegmentSize; - bool m_bufferFilled; - bool m_newList; - int m_streamlenght; - - uchar* m_pBuffer; - - Poco::Net::HTTPClientSession* m_pClientSession; - plexclient::cVideo* m_pVideo; - Poco::URI m_startUri; - std::string m_sessionUriPart; - std::string m_segmentUriPart; - std::string m_sessionCookie; - - cM3u8Parser m_startParser; - cM3u8Parser m_indexParser; - - bool ConnectToServer(void); - void CloseConnection(void); - bool LoadStartList(void); - bool LoadIndexList(void); - std::string GetSegmentUri(int segmentIndex) const; - int GetSegmentSize(int segmentIndex); - bool LoadSegment(std::string uri); - int EstimateSegmentSize(); - bool LoadLists(void); - void ResizeRingbuffer(int newsize); - void SkipEmptySegments(int segmentLenght); - + int m_ringBufferSize; + unsigned int m_segmentsToBuffer; + unsigned int m_lastLoadedSegment; + int m_lastSegmentSize; + bool m_bufferFilled; + bool m_newList; + int m_streamlenght; + + uchar *m_pBuffer; + + Poco::Net::HTTPClientSession *m_pClientSession; + plexclient::cVideo *m_pVideo; + Poco::URI m_startUri; + std::string m_sessionUriPart; + std::string m_segmentUriPart; + std::string m_sessionCookie; + + cM3u8Parser m_startParser; + cM3u8Parser m_indexParser; + + bool ConnectToServer(void); + + void CloseConnection(void); + + bool LoadStartList(void); + + bool LoadIndexList(void); + + std::string GetSegmentUri(int segmentIndex) const; + + int GetSegmentSize(int segmentIndex); + + bool LoadSegment(std::string uri); + + int EstimateSegmentSize(); + + bool LoadLists(void); + + void ResizeRingbuffer(int newsize); + + void SkipEmptySegments(int segmentLenght); + protected: - void Action(void); - bool DoLoad(void); + void Action(void); + + bool DoLoad(void); public: - cHlsSegmentLoader(std::string startm3u8, plexclient::cVideo* pVideo); - ~cHlsSegmentLoader(); - - cRingBufferLinear* m_pRingbuffer; - bool BufferFilled(void); - bool Active(void); - bool StopLoader(void); - bool LoadM3u8(std::string uri); - void AddHeader(Poco::Net::HTTPRequest& req); - void Ping(void); - int GetStreamLenght(); + cHlsSegmentLoader(std::string startm3u8, plexclient::cVideo *pVideo); + + ~cHlsSegmentLoader(); + + cRingBufferLinear *m_pRingbuffer; + + bool BufferFilled(void); + + bool Active(void); + + bool StopLoader(void); + + bool LoadM3u8(std::string uri); + + void AddHeader(Poco::Net::HTTPRequest &req); + + void Ping(void); + + int GetStreamLenght(); }; -class cHlsPlayer : public cPlayer, cThread -{ +class cHlsPlayer : public cPlayer, cThread { private: - std::ofstream* m_pDebugFile; - int AudioIndexOffset; - cHlsSegmentLoader* m_pSegmentLoader; - plexclient::cVideo m_Video; - - int m_jumpOffset; - int m_timeOffset; - bool m_doJump; - bool m_isBuffering; - - int m_videoLenght; - int m_actualSegment; - int m_actualTime; - long m_lastValidSTC; - - unsigned long long m_tLastTime; - unsigned long long m_tTimeSum; - bool m_bFirstPlay; - cTimeMs m_tTimer; - - enum ePlayModes { pmPlay, pmPause }; - ePlayModes playMode; - - virtual void Activate(bool On); - int GetPlayedSeconds(void); - void CountPlayedSeconds(void); - void ResetPlayedSeconds(void); - void ReportProgress(bool stopped = false); - void SetWatched(void); + std::ofstream *m_pDebugFile; + int AudioIndexOffset; + cHlsSegmentLoader *m_pSegmentLoader; + plexclient::cVideo m_Video; + + int m_jumpOffset; + int m_timeOffset; + bool m_doJump; + bool m_isBuffering; + + int m_videoLenght; + int m_actualSegment; + int m_actualTime; + long m_lastValidSTC; + + unsigned long long m_tLastTime; + unsigned long long m_tTimeSum; + bool m_bFirstPlay; + cTimeMs m_tTimer; + + enum ePlayModes { + pmPlay, pmPause + }; + ePlayModes playMode; + + virtual void Activate(bool On); + + int GetPlayedSeconds(void); + + void CountPlayedSeconds(void); + + void ResetPlayedSeconds(void); + + void ReportProgress(bool stopped = false); + + void SetWatched(void); protected: - void Action(void); - bool DoPlay(void); + void Action(void); + + bool DoPlay(void); public: - //static cMutex s_mutex; - cHlsPlayer(std::string startm3u8, plexclient::cVideo Video, int offset = 0); - ~cHlsPlayer(); - - virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); - virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); - virtual double FramesPerSecond(void); - virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId); - void Pause(void); - void Play(void); - void Stop(void); - bool Active(void); - void JumpTo(int seconds); - void JumpRelative(int seconds); - void SetAudioAndSubtitleTracks(void); + //static cMutex s_mutex; + cHlsPlayer(std::string startm3u8, plexclient::cVideo Video, int offset = 0); + + ~cHlsPlayer(); + + virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + + virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); + + virtual double FramesPerSecond(void); + + virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId); + + void Pause(void); + + void Play(void); + + void Stop(void); + + bool Active(void); + + void JumpTo(int seconds); + + void JumpRelative(int seconds); + + void SetAudioAndSubtitleTracks(void); }; diff --git a/hlsPlayerControl.cpp b/hlsPlayerControl.cpp index 50ba441..f5068be 100644 --- a/hlsPlayerControl.cpp +++ b/hlsPlayerControl.cpp @@ -13,379 +13,365 @@ #include "cPlexOsdItem.h" // static -cControl* cHlsPlayerControl::Create(plexclient::cVideo Video) -{ - // Stop already playing stream - cHlsPlayerControl* c = dynamic_cast<cHlsPlayerControl*>(cControl::Control(true)); - if(c) { - c->Stop(); - } - - // get Metadata - std::string uri = Video.m_pServer->GetUri() + Video.m_sKey; - auto pmcontainer = plexclient::Plexservice::GetMediaContainer(uri); - if(pmcontainer == NULL) return NULL; - - std::string transcodeUri = plexclient::Plexservice::GetUniversalTranscodeUrl(&pmcontainer->m_vVideos[0], Video.m_iMyPlayOffset); - cHlsPlayerControl* playerControl = new cHlsPlayerControl(new cHlsPlayer(transcodeUri, pmcontainer->m_vVideos[0], Video.m_iMyPlayOffset), pmcontainer->m_vVideos[0]); - playerControl->m_title = pmcontainer->m_vVideos[0].m_sTitle; - return playerControl; +cControl *cHlsPlayerControl::Create(plexclient::cVideo Video) { + // Stop already playing stream + cHlsPlayerControl *c = dynamic_cast<cHlsPlayerControl *>(cControl::Control(true)); + if (c) { + c->Stop(); + } + + // get Metadata + std::string uri = Video.m_pServer->GetUri() + Video.m_sKey; + auto pmcontainer = plexclient::Plexservice::GetMediaContainer(uri); + if (pmcontainer == NULL) return NULL; + + std::string transcodeUri = plexclient::Plexservice::GetUniversalTranscodeUrl(&pmcontainer->m_vVideos[0], + Video.m_iMyPlayOffset); + cHlsPlayerControl *playerControl = new cHlsPlayerControl( + new cHlsPlayer(transcodeUri, pmcontainer->m_vVideos[0], Video.m_iMyPlayOffset), pmcontainer->m_vVideos[0]); + playerControl->m_title = pmcontainer->m_vVideos[0].m_sTitle; + return playerControl; } -cHlsPlayerControl::cHlsPlayerControl(cHlsPlayer* Player, plexclient::cVideo Video) :cControl(Player) -{ - dsyslog("[plex]: '%s'", __FUNCTION__); - player = Player; - m_Video = Video; - //m_title = title; - - displayReplay = NULL; - visible = modeOnly = shown = false; - lastCurrent = lastTotal = -1; - lastPlay = lastForward = false; - lastSpeed = -2; // an invalid value - timeoutShow = 0; - menu = NULL; - - cStatus::MsgReplaying(this, m_title.c_str(), m_Video.m_Media.m_sPartFile.c_str(), true); +cHlsPlayerControl::cHlsPlayerControl(cHlsPlayer *Player, plexclient::cVideo Video) : cControl(Player) { + dsyslog("[plex]: '%s'", __FUNCTION__); + player = Player; + m_Video = Video; + //m_title = title; + + displayReplay = NULL; + visible = modeOnly = shown = false; + lastCurrent = lastTotal = -1; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value + timeoutShow = 0; + menu = NULL; + + cStatus::MsgReplaying(this, m_title.c_str(), m_Video.m_Media.m_sPartFile.c_str(), true); } -cHlsPlayerControl::~cHlsPlayerControl() -{ - dsyslog("[plex]: '%s'", __FUNCTION__); - cStatus::MsgReplaying(this, NULL, NULL, false); - Hide(); - delete player; - delete menu; - player = NULL; +cHlsPlayerControl::~cHlsPlayerControl() { + dsyslog("[plex]: '%s'", __FUNCTION__); + cStatus::MsgReplaying(this, NULL, NULL, false); + Hide(); + delete player; + delete menu; + player = NULL; } -cString cHlsPlayerControl::GetHeader(void) -{ - return m_title.c_str(); +cString cHlsPlayerControl::GetHeader(void) { + return m_title.c_str(); } -void cHlsPlayerControl::Hide(void) -{ - if (visible) { - delete displayReplay; - displayReplay = NULL; - SetNeedsFastResponse(false); - visible = false; - modeOnly = false; - lastPlay = lastForward = false; - lastSpeed = -2; // an invalid value - //timeSearchActive = false; - timeoutShow = 0; - } +void cHlsPlayerControl::Hide(void) { + if (visible) { + delete displayReplay; + displayReplay = NULL; + SetNeedsFastResponse(false); + visible = false; + modeOnly = false; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value + //timeSearchActive = false; + timeoutShow = 0; + } } -void cHlsPlayerControl::Show(void) -{ - ShowTimed(3); +void cHlsPlayerControl::Show(void) { + ShowTimed(3); } -eOSState cHlsPlayerControl::ProcessKey(eKeys Key) -{ - if (!Active()) - return osEnd; - if (Key == kPlayPause) { - bool Play, Forward; - int Speed; - GetReplayMode(Play, Forward, Speed); - if (Speed >= 0) - Key = Play ? kPlay : kPause; - else - Key = Play ? kPause : kPlay; - } - if (visible) { - if (timeoutShow && time(NULL) > timeoutShow) { - Hide(); - ShowMode(); - timeoutShow = 0; - } else if (modeOnly) - ShowMode(); - else - shown = ShowProgress(!shown) || shown; - } - - // Handle menus - if (menu) { - eOSState state = menu->ProcessKey(Key); - if (state == osEnd) { - JumpRelative(0); - delete menu; - menu = NULL; - } - if (state == osBack) { - Hide(); - delete menu; - menu = NULL; - } - return osContinue; - } - - bool DoShowMode = true; - switch (int(Key)) { - // Positioning: - case kPlay: - case kUp: - Play(); - break; - case kPause: - case kDown: - Pause(); - break; - case kFastRew: - case kLeft: - player->JumpRelative(-10); - break; - case kFastFwd: - case kRight: - player->JumpRelative(10); - break; - case kGreen|k_Repeat: +eOSState cHlsPlayerControl::ProcessKey(eKeys Key) { + if (!Active()) + return osEnd; + if (Key == kPlayPause) { + bool Play, Forward; + int Speed; + GetReplayMode(Play, Forward, Speed); + if (Speed >= 0) + Key = Play ? kPlay : kPause; + else + Key = Play ? kPause : kPlay; + } + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); + ShowMode(); + timeoutShow = 0; + } else if (modeOnly) + ShowMode(); + else + shown = ShowProgress(!shown) || shown; + } + + // Handle menus + if (menu) { + eOSState state = menu->ProcessKey(Key); + if (state == osEnd) { + JumpRelative(0); + delete menu; + menu = NULL; + } + if (state == osBack) { + Hide(); + delete menu; + menu = NULL; + } + return osContinue; + } + + bool DoShowMode = true; + switch (int(Key)) { + // Positioning: + case kPlay: + case kUp: + Play(); + break; + case kPause: + case kDown: + Pause(); + break; + case kFastRew: + case kLeft: + player->JumpRelative(-10); + break; + case kFastFwd: + case kRight: + player->JumpRelative(10); + break; + case kGreen | k_Repeat: #if APIVERSNUM >= 20200 - player->JumpRelative(-Setup.SkipSecondsRepeat); - break; + player->JumpRelative(-Setup.SkipSecondsRepeat); + break; #endif - case kGreen: + case kGreen: #if APIVERSNUM >= 20200 - player->JumpRelative(-Setup.SkipSeconds); + player->JumpRelative(-Setup.SkipSeconds); #else - player->JumpRelative(-300); + player->JumpRelative(-300); #endif - break; - case kYellow|k_Repeat: + break; + case kYellow | k_Repeat: #if APIVERSNUM >= 20200 - player->JumpRelative(Setup.SkipSecondsRepeat); - break; + player->JumpRelative(Setup.SkipSecondsRepeat); + break; #endif - case kYellow: + case kYellow: #if APIVERSNUM >= 20200 - player->JumpRelative(Setup.SkipSeconds); + player->JumpRelative(Setup.SkipSeconds); #else - player->JumpRelative(300); + player->JumpRelative(300); #endif - break; - case kStop: - case kBlue: - Hide(); - Stop(); - cMyPlugin::CalledFromCode = true; - cRemote::CallPlugin(PLUGIN); - return osEnd; - default: { - DoShowMode = false; - switch (int(Key)) { - default: { - switch (Key) { - case kOk: - if (visible && !modeOnly) { - Hide(); - DoShowMode = true; - } else - Show(); - break; - case kBack: - Hide(); - menu = new cStreamSelectMenu(&m_Video); - break; - default: - return osUnknown; - } - } - } - } - if (DoShowMode) - ShowMode(); - } - - return osContinue; + break; + case kStop: + case kBlue: + Hide(); + Stop(); + cMyPlugin::CalledFromCode = true; + cRemote::CallPlugin(PLUGIN); + return osEnd; + default: { + DoShowMode = false; + switch (int(Key)) { + default: { + switch (Key) { + case kOk: + if (visible && !modeOnly) { + Hide(); + DoShowMode = true; + } else + Show(); + break; + case kBack: + Hide(); + menu = new cStreamSelectMenu(&m_Video); + break; + default: + return osUnknown; + } + } + } + } + if (DoShowMode) + ShowMode(); + } + + return osContinue; } -bool cHlsPlayerControl::Active(void) -{ - return player && player->Active(); +bool cHlsPlayerControl::Active(void) { + return player && player->Active(); } -void cHlsPlayerControl::Pause(void) -{ - if(player) - player->Pause(); +void cHlsPlayerControl::Pause(void) { + if (player) + player->Pause(); } -void cHlsPlayerControl::Play(void) -{ - if(player) - player->Play(); +void cHlsPlayerControl::Play(void) { + if (player) + player->Play(); } -void cHlsPlayerControl::Stop(void) -{ - if(player) - player->Stop(); +void cHlsPlayerControl::Stop(void) { + if (player) + player->Stop(); } -void cHlsPlayerControl::SeekTo(int offset) -{ - if (player) { - player->JumpTo(offset); - } +void cHlsPlayerControl::SeekTo(int offset) { + if (player) { + player->JumpTo(offset); + } } -void cHlsPlayerControl::JumpRelative(int offset) -{ - if (player) - player->JumpRelative(offset); +void cHlsPlayerControl::JumpRelative(int offset) { + if (player) + player->JumpRelative(offset); } -void cHlsPlayerControl::ShowMode(void) -{ - //dsyslog("[plex]: '%s'\n", __FUNCTION__); - if (visible || (Setup.ShowReplayMode && !cOsd::IsOpen())) { - bool Play, Forward; - int Speed; - if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) { - bool NormalPlay = (Play && Speed == -1); - - if (!visible) { - if (NormalPlay) - return; // no need to do indicate ">" unless there was a different mode displayed before - visible = modeOnly = true; - displayReplay = Skins.Current()->DisplayReplay(modeOnly); - } - - if (modeOnly && !timeoutShow && NormalPlay) - timeoutShow = time(NULL) + 3; - displayReplay->SetMode(Play, Forward, Speed); - lastPlay = Play; - lastForward = Forward; - lastSpeed = Speed; - } - } +void cHlsPlayerControl::ShowMode(void) { + //dsyslog("[plex]: '%s'\n", __FUNCTION__); + if (visible || (Setup.ShowReplayMode && !cOsd::IsOpen())) { + bool Play, Forward; + int Speed; + if (GetReplayMode(Play, Forward, Speed) && + (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) { + bool NormalPlay = (Play && Speed == -1); + + if (!visible) { + if (NormalPlay) + return; // no need to do indicate ">" unless there was a different mode displayed before + visible = modeOnly = true; + displayReplay = Skins.Current()->DisplayReplay(modeOnly); + } + + if (modeOnly && !timeoutShow && NormalPlay) + timeoutShow = time(NULL) + 3; + displayReplay->SetMode(Play, Forward, Speed); + lastPlay = Play; + lastForward = Forward; + lastSpeed = Speed; + } + } } -bool cHlsPlayerControl::ShowProgress(bool Initial) -{ - int Current, Total; - - if (GetIndex(Current, Total)) { - if (!visible) { - displayReplay = Skins.Current()->DisplayReplay(modeOnly); - displayReplay->SetButtons(NULL,tr("Skip Back"),tr("Skip Forward"),tr("Stop")); - SetNeedsFastResponse(true); - visible = true; - } - if (Initial) { - lastCurrent = lastTotal = -1; - } - if (Current != lastCurrent || Total != lastTotal) { - if (Setup.ShowRemainingTime || Total != lastTotal) { - int Index = Total; - if (Setup.ShowRemainingTime) - Index = Current - Index; - displayReplay->SetTotal(IndexToHMSF(Index, false, FramesPerSecond())); - if (!Initial) - displayReplay->Flush(); - } - displayReplay->SetProgress(Current, Total); - if (!Initial) - displayReplay->Flush(); - displayReplay->SetCurrent(IndexToHMSF(Current, false, FramesPerSecond())); - displayReplay->SetTitle(m_title.c_str()); - displayReplay->Flush(); - lastCurrent = Current; - } - lastTotal = Total; - ShowMode(); - return true; - } - return false; +bool cHlsPlayerControl::ShowProgress(bool Initial) { + int Current, Total; + + if (GetIndex(Current, Total)) { + if (!visible) { + displayReplay = Skins.Current()->DisplayReplay(modeOnly); + displayReplay->SetButtons(NULL, tr("Skip Back"), tr("Skip Forward"), tr("Stop")); + SetNeedsFastResponse(true); + visible = true; + } + if (Initial) { + lastCurrent = lastTotal = -1; + } + if (Current != lastCurrent || Total != lastTotal) { + if (Setup.ShowRemainingTime || Total != lastTotal) { + int Index = Total; + if (Setup.ShowRemainingTime) + Index = Current - Index; + displayReplay->SetTotal(IndexToHMSF(Index, false, FramesPerSecond())); + if (!Initial) + displayReplay->Flush(); + } + displayReplay->SetProgress(Current, Total); + if (!Initial) + displayReplay->Flush(); + displayReplay->SetCurrent(IndexToHMSF(Current, false, FramesPerSecond())); + displayReplay->SetTitle(m_title.c_str()); + displayReplay->Flush(); + lastCurrent = Current; + } + lastTotal = Total; + ShowMode(); + return true; + } + return false; } -void cHlsPlayerControl::ShowTimed(int Seconds) -{ - if (modeOnly) - Hide(); - if (!visible) { - shown = ShowProgress(true); - timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; - } else if (timeoutShow && Seconds > 0) - timeoutShow = time(NULL) + Seconds; +void cHlsPlayerControl::ShowTimed(int Seconds) { + if (modeOnly) + Hide(); + if (!visible) { + shown = ShowProgress(true); + timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; + } else if (timeoutShow && Seconds > 0) + timeoutShow = time(NULL) + Seconds; } -cStreamSelectMenu::cStreamSelectMenu(plexclient::cVideo* Video) : cOsdMenu("StreamSelect") -{ - pVideo = Video; - CreateMenu(); +cStreamSelectMenu::cStreamSelectMenu(plexclient::cVideo *Video) : cOsdMenu("StreamSelect") { + pVideo = Video; + CreateMenu(); } -void cStreamSelectMenu::CreateMenu() -{ - SetTitle(cString::sprintf(tr("%s - Select Audio / Subtitle"), pVideo->GetTitle().c_str())); - pVideo->UpdateFromServer(); - - if(pVideo->m_Media.m_vStreams.size() > 0) { - std::vector<plexclient::Stream> streams = pVideo->m_Media.m_vStreams; - - Add(new cOsdItem(tr("Audiostreams"), osUnknown, false)); - for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { - plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::StreamType::sAUDIO) { - // Audio - cString item = cString::sprintf(tr("%s%s - %s %d Channels"), pStream->m_bSelected ? "[*] ":"", pStream->m_sLanguage.c_str(), pStream->m_sCodecId.c_str(), pStream->m_iChannels); - Add(new cPlexOsdItem(item, pStream)); - } - } - - Add(new cOsdItem(tr("Subtitlestreams"), osUnknown, false)); - plexclient::Stream stre; - stre.m_eStreamType = plexclient::StreamType::sSUBTITLE; - stre.m_iID = -1; - Add(new cPlexOsdItem(tr("None"), &stre)); - for(std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { - plexclient::Stream *pStream = &(*it); - if(pStream->m_eStreamType == plexclient::StreamType::sSUBTITLE) { - // Subtitle - cString item = cString::sprintf("%s%s", pStream->m_bSelected ? "[*] ":"", pStream->m_sLanguage.c_str()); - Add(new cPlexOsdItem(item, pStream)); - } - } - } - - Display(); +void cStreamSelectMenu::CreateMenu() { + SetTitle(cString::sprintf(tr("%s - Select Audio / Subtitle"), pVideo->GetTitle().c_str())); + pVideo->UpdateFromServer(); + + if (pVideo->m_Media.m_vStreams.size() > 0) { + std::vector<plexclient::Stream> streams = pVideo->m_Media.m_vStreams; + + Add(new cOsdItem(tr("Audiostreams"), osUnknown, false)); + for (std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { + plexclient::Stream *pStream = &(*it); + if (pStream->m_eStreamType == plexclient::StreamType::sAUDIO) { + // Audio + cString item = cString::sprintf(tr("%s%s - %s %d Channels"), pStream->m_bSelected ? "[*] " : "", + pStream->m_sLanguage.c_str(), pStream->m_sCodecId.c_str(), + pStream->m_iChannels); + Add(new cPlexOsdItem(item, pStream)); + } + } + + Add(new cOsdItem(tr("Subtitlestreams"), osUnknown, false)); + plexclient::Stream stre; + stre.m_eStreamType = plexclient::StreamType::sSUBTITLE; + stre.m_iID = -1; + Add(new cPlexOsdItem(tr("None"), &stre)); + for (std::vector<plexclient::Stream>::iterator it = streams.begin(); it != streams.end(); ++it) { + plexclient::Stream *pStream = &(*it); + if (pStream->m_eStreamType == plexclient::StreamType::sSUBTITLE) { + // Subtitle + cString item = cString::sprintf("%s%s", pStream->m_bSelected ? "[*] " : "", + pStream->m_sLanguage.c_str()); + Add(new cPlexOsdItem(item, pStream)); + } + } + } + + Display(); } -bool cStreamSelectMenu::SelectStream() -{ - int current = Current(); // get current menu item index - cPlexOsdItem *item = static_cast<cPlexOsdItem*>(Get(current)); - return pVideo->SetStream(&item->GetAttachedStream()); +bool cStreamSelectMenu::SelectStream() { + int current = Current(); // get current menu item index + cPlexOsdItem *item = static_cast<cPlexOsdItem *>(Get(current)); + return pVideo->SetStream(&item->GetAttachedStream()); } -eOSState cStreamSelectMenu::ProcessKey(eKeys Keys) -{ - eOSState state; - - // call standard function - state = cOsdMenu::ProcessKey(Keys); - - switch (state) { - case osUnknown: - switch (Keys) { - case kOk: - return SelectStream() ? osEnd : osBack; - case kBack: - return osBack; - default: - break; - } - break; - case osBack: - return osBack; - default: - break; - } - return state; +eOSState cStreamSelectMenu::ProcessKey(eKeys Keys) { + eOSState state; + + // call standard function + state = cOsdMenu::ProcessKey(Keys); + + switch (state) { + case osUnknown: + switch (Keys) { + case kOk: + return SelectStream() ? osEnd : osBack; + case kBack: + return osBack; + default: + break; + } + break; + case osBack: + return osBack; + default: + break; + } + return state; } diff --git a/hlsPlayerControl.h b/hlsPlayerControl.h index c208502..b777c40 100644 --- a/hlsPlayerControl.h +++ b/hlsPlayerControl.h @@ -8,60 +8,71 @@ #include "MediaContainer.h" #include "PVideo.h" -class cStreamSelectMenu : public cOsdMenu -{ +class cStreamSelectMenu : public cOsdMenu { private: - plexclient::cVideo* pVideo; - void CreateMenu(); - bool SelectStream(); - + plexclient::cVideo *pVideo; + + void CreateMenu(); + + bool SelectStream(); + public: - cStreamSelectMenu(plexclient::cVideo* Video); - virtual eOSState ProcessKey(eKeys Keys); + cStreamSelectMenu(plexclient::cVideo *Video); + + virtual eOSState ProcessKey(eKeys Keys); }; -class cHlsPlayerControl : public cControl -{ +class cHlsPlayerControl : public cControl { private: - static volatile int active; - cHlsPlayer* player; - std::string m_title; - - cStreamSelectMenu* menu; - cSkinDisplayReplay *displayReplay; - bool visible, modeOnly, shown; - int lastCurrent, lastTotal; - bool lastPlay, lastForward; - int lastSpeed; - time_t timeoutShow; - - void ShowMode(void); - bool ShowProgress(bool Initial); - void ShowTimed(int Seconds = 0); + static volatile int active; + cHlsPlayer *player; + std::string m_title; + + cStreamSelectMenu *menu; + cSkinDisplayReplay *displayReplay; + bool visible, modeOnly, shown; + int lastCurrent, lastTotal; + bool lastPlay, lastForward; + int lastSpeed; + time_t timeoutShow; + + void ShowMode(void); + + bool ShowProgress(bool Initial); + + void ShowTimed(int Seconds = 0); protected: - //void ShowMode(); + //void ShowMode(); public: - plexclient::cVideo m_Video; + plexclient::cVideo m_Video; + + static cControl *Create(plexclient::cVideo Video); + + cHlsPlayerControl(cHlsPlayer *Player, plexclient::cVideo Video); + + virtual ~cHlsPlayerControl(); + + virtual void Show(void); + + virtual void Hide(void); + + virtual cString GetHeader(void); + + virtual eOSState ProcessKey(eKeys Key); + + bool Active(void); - static cControl* Create(plexclient::cVideo Video); - cHlsPlayerControl(cHlsPlayer* Player, plexclient::cVideo Video); - virtual ~cHlsPlayerControl(); + void Pause(void); - virtual void Show(void); - virtual void Hide(void); + void Play(void); - virtual cString GetHeader(void); - virtual eOSState ProcessKey(eKeys Key); + void Stop(void); - bool Active(void); + void SeekTo(int offset); - void Pause(void); - void Play(void); - void Stop(void); - void SeekTo(int offset); - void JumpRelative(int offset); + void JumpRelative(int offset); }; diff --git a/m3u8Parser.cpp b/m3u8Parser.cpp index 9c2657f..35b6747 100644 --- a/m3u8Parser.cpp +++ b/m3u8Parser.cpp @@ -2,116 +2,113 @@ #include <pcrecpp.h> #include <vdr/tools.h> -cM3u8Parser::cM3u8Parser() -{ - Init(); +cM3u8Parser::cM3u8Parser() { + Init(); } -cM3u8Parser::cM3u8Parser(std::istream& m3u8) -{ - Init(); - Parse(m3u8); + +cM3u8Parser::cM3u8Parser(std::istream &m3u8) { + Init(); + Parse(m3u8); } -void cM3u8Parser::Init() -{ - TargetDuration = -1; - MediaSequence = -1; - MasterPlaylist = false; - AllowCache = true; + +void cM3u8Parser::Init() { + TargetDuration = -1; + MediaSequence = -1; + MasterPlaylist = false; + AllowCache = true; } -bool cM3u8Parser::Parse(std::istream& m3u8) -{ - bool ok = true; - bool nextLineIsMedia = false; - int lineNo = 0; +bool cM3u8Parser::Parse(std::istream &m3u8) { + bool ok = true; + bool nextLineIsMedia = false; + int lineNo = 0; - // prepare regex - pcrecpp::RE re("#(EXT[^:\\n]+)(?::[^\\n]+)"); - pcrecpp::RE reVal("(?::([^\\n]+))"); + // prepare regex + pcrecpp::RE re("#(EXT[^:\\n]+)(?::[^\\n]+)"); + pcrecpp::RE reVal("(?::([^\\n]+))"); - std::string line; - playListItem pItem; - pItem.bandwidth = -1; - pItem.file = ""; - pItem.length = -1; - pItem.programId = -1; + std::string line; + playListItem pItem; + pItem.bandwidth = -1; + pItem.file = ""; + pItem.length = -1; + pItem.programId = -1; - while (std::getline(m3u8, line)) { - if(lineNo == 0 && "#EXTM3U" == line ) { - lineNo++; - continue; - } else if(lineNo == 0) { - // Invalid File - ok = false; - esyslog("[plex]%s m3u8 is invalid. dumping File:", __FUNCTION__); - esyslog("[plex]%s", line.c_str()); - eDump(m3u8); - break; - } + while (std::getline(m3u8, line)) { + if (lineNo == 0 && "#EXTM3U" == line) { + lineNo++; + continue; + } else if (lineNo == 0) { + // Invalid File + ok = false; + esyslog("[plex]%s m3u8 is invalid. dumping File:", __FUNCTION__); + esyslog("[plex]%s", line.c_str()); + eDump(m3u8); + break; + } - if( re.FullMatch(line) ) { - string var; - //string value; - re.PartialMatch(line, &var); - if("EXT-X-TARGETDURATION" == var) { - int value; - reVal.PartialMatch(line, &value); - TargetDuration = value; - } else if ("EXT-X-ALLOW-CACHE" == var) { - string value; - reVal.PartialMatch(line, &value); - AllowCache = "YES" == value; - } else if ("EXT-X-MEDIA-SEQUENCE" == var) { - int value; - reVal.PartialMatch(line, &value); - MediaSequence = value; - } else if ("EXT-X-STREAM-INF" == var) { - MasterPlaylist = true; - nextLineIsMedia = true; + if (re.FullMatch(line)) { + string var; + //string value; + re.PartialMatch(line, &var); + if ("EXT-X-TARGETDURATION" == var) { + int value; + reVal.PartialMatch(line, &value); + TargetDuration = value; + } else if ("EXT-X-ALLOW-CACHE" == var) { + string value; + reVal.PartialMatch(line, &value); + AllowCache = "YES" == value; + } else if ("EXT-X-MEDIA-SEQUENCE" == var) { + int value; + reVal.PartialMatch(line, &value); + MediaSequence = value; + } else if ("EXT-X-STREAM-INF" == var) { + MasterPlaylist = true; + nextLineIsMedia = true; - int bandw; - pcrecpp::RE reBand("BANDWIDTH=(\\d+)"); - if(reBand.PartialMatch(line, &bandw)) { - pItem.bandwidth = bandw; - } + int bandw; + pcrecpp::RE reBand("BANDWIDTH=(\\d+)"); + if (reBand.PartialMatch(line, &bandw)) { + pItem.bandwidth = bandw; + } - int id; - pcrecpp::RE reId("PROGRAM-ID=(\\d+)"); - if(reId.PartialMatch(line, &id)) { - pItem.programId = id; - } + int id; + pcrecpp::RE reId("PROGRAM-ID=(\\d+)"); + if (reId.PartialMatch(line, &id)) { + pItem.programId = id; + } - } else if ("EXTINF" == var) { - MasterPlaylist = false; - int value; - pcrecpp::RE reInt("(?:#EXTINF:([\\d]+))"); - if( reInt.PartialMatch(line, &value)) { - nextLineIsMedia = true; - pItem.length = value; - } - } - } - // possible mediafile - else { - if(nextLineIsMedia) { - nextLineIsMedia = false; - pItem.file = line; - pItem.size = 0; - vPlaylistItems.push_back(pItem); - } - } - lineNo++; - } - return ok; + } else if ("EXTINF" == var) { + MasterPlaylist = false; + int value; + pcrecpp::RE reInt("(?:#EXTINF:([\\d]+))"); + if (reInt.PartialMatch(line, &value)) { + nextLineIsMedia = true; + pItem.length = value; + } + } + } + // possible mediafile + else { + if (nextLineIsMedia) { + nextLineIsMedia = false; + pItem.file = line; + pItem.size = 0; + vPlaylistItems.push_back(pItem); + } + } + lineNo++; + } + return ok; } -void cM3u8Parser::eDump(std::istream &m3u8) -{ - std::string line; - while (std::getline(m3u8, line)) { - esyslog("[plex]%s", line.c_str()); - } +void cM3u8Parser::eDump(std::istream &m3u8) { + std::string line; + while (std::getline(m3u8, line)) { + esyslog("[plex]%s", line.c_str()); + } } /* diff --git a/m3u8Parser.h b/m3u8Parser.h index 3bd0ae2..ed915f9 100644 --- a/m3u8Parser.h +++ b/m3u8Parser.h @@ -5,32 +5,35 @@ #include <string> #include <iostream> -class cM3u8Parser -{ +class cM3u8Parser { public: - struct playListItem { - int length; - int bandwidth; - int programId; - std::string file; - int size; - }; + struct playListItem { + int length; + int bandwidth; + int programId; + std::string file; + int size; + }; private: - void Init(); - void eDump(std::istream &m3u8); + void Init(); + + void eDump(std::istream &m3u8); public: - std::vector<playListItem> vPlaylistItems; - int TargetDuration; - int MediaSequence; - bool MasterPlaylist; - bool AllowCache; - bool Parse(std::istream &m3u8); + std::vector<playListItem> vPlaylistItems; + int TargetDuration; + int MediaSequence; + bool MasterPlaylist; + bool AllowCache; + + bool Parse(std::istream &m3u8); public: - cM3u8Parser(std::istream &m3u8); - cM3u8Parser(); - ~cM3u8Parser() {}; + cM3u8Parser(std::istream &m3u8); + + cM3u8Parser(); + + ~cM3u8Parser() { }; }; diff --git a/pictureCache.cpp b/pictureCache.cpp index 2fcc6eb..af0871a 100644 --- a/pictureCache.cpp +++ b/pictureCache.cpp @@ -18,149 +18,147 @@ using Poco::StreamCopier; using Poco::Path; using Poco::Exception; -cPictureCache::cPictureCache() -{ - m_cacheDir = cPlugin::CacheDirectory(PLUGIN_NAME_I18N); - - Poco::Path path(m_cacheDir); - Poco::File f(path.toString()); - f.createDirectories(); - m_bAllInvalidated = false; +cPictureCache::cPictureCache() { + m_cacheDir = cPlugin::CacheDirectory(PLUGIN_NAME_I18N); + + Poco::Path path(m_cacheDir); + Poco::File f(path.toString()); + f.createDirectories(); + m_bAllInvalidated = false; } -bool cPictureCache::DownloadFileAndSave(std::string Uri, std::string localFile) -{ - try { - Poco::URI fileUri(Uri); - plexclient::PlexServer* pServer = plexclient::plexgdm::GetInstance().GetServer(fileUri.getHost(), fileUri.getPort()); - - bool ok; - auto cSession = pServer->MakeRequest(ok, fileUri.getPathAndQuery()); - Poco::Net::HTTPResponse response; - std::istream &rs = cSession->receiveResponse(response); - - if (!ok || response.getStatus() != 200) - return false; - - std::string type = response.getContentType(); - std::string fileName = localFile; - - // check filetype - char buffer[2]; - rs.read(buffer, 2); - bool isPng = false; - - if(buffer[0] == char(0x89) && buffer[1] == char(0x50) ) { - isPng = true; - } - rs.putback(buffer[1]); - rs.putback(buffer[0]); - - if(isPng) { - fileName += ".png"; - } else if(type == "image/jpeg" || fileUri.getPathAndQuery().find(".jpg") != std::string::npos) { - fileName += ".jpg"; - } - - Poco::Path p(fileName); - Poco::File f(p.makeParent().toString()); - f.createDirectories(); - - std::ofstream outFile; - outFile.open(fileName); - Poco::StreamCopier::copyStream(rs, outFile); - outFile.close(); - return true; - } catch (Poco::Exception &exc) { - std::cout << exc.displayText() << std::endl; - return false; - } +bool cPictureCache::DownloadFileAndSave(std::string Uri, std::string localFile) { + try { + Poco::URI fileUri(Uri); + plexclient::PlexServer *pServer = plexclient::plexgdm::GetInstance().GetServer(fileUri.getHost(), + fileUri.getPort()); + + bool ok; + auto cSession = pServer->MakeRequest(ok, fileUri.getPathAndQuery()); + Poco::Net::HTTPResponse response; + std::istream &rs = cSession->receiveResponse(response); + + if (!ok || response.getStatus() != 200) + return false; + + std::string type = response.getContentType(); + std::string fileName = localFile; + + // check filetype + char buffer[2]; + rs.read(buffer, 2); + bool isPng = false; + + if (buffer[0] == char(0x89) && buffer[1] == char(0x50)) { + isPng = true; + } + rs.putback(buffer[1]); + rs.putback(buffer[0]); + + if (isPng) { + fileName += ".png"; + } else if (type == "image/jpeg" || fileUri.getPathAndQuery().find(".jpg") != std::string::npos) { + fileName += ".jpg"; + } + + Poco::Path p(fileName); + Poco::File f(p.makeParent().toString()); + f.createDirectories(); + + std::ofstream outFile; + outFile.open(fileName); + Poco::StreamCopier::copyStream(rs, outFile); + outFile.close(); + return true; + } catch (Poco::Exception &exc) { + std::cout << exc.displayText() << std::endl; + return false; + } } -std::string cPictureCache::FileName(std::string uri, int width) -{ - Poco::URI u(uri); - plexclient::PlexServer* pServer = plexclient::plexgdm::GetInstance().GetServer(u.getHost(), u.getPort()); - std::string uuid = "default"; - if(pServer && !pServer->GetUuid().empty()) { - uuid = pServer->GetUuid(); - } - std::string file = Poco::format("%s/%s_%d", uuid, u.getPathAndQuery(), width); +std::string cPictureCache::FileName(std::string uri, int width) { + Poco::URI u(uri); + plexclient::PlexServer *pServer = plexclient::plexgdm::GetInstance().GetServer(u.getHost(), u.getPort()); + std::string uuid = "default"; + if (pServer && !pServer->GetUuid().empty()) { + uuid = pServer->GetUuid(); + } + std::string file = Poco::format("%s/%s_%d", uuid, u.getPathAndQuery(), width); - Poco::Path path(m_cacheDir); - path.append(file); + Poco::Path path(m_cacheDir); + path.append(file); - return path.toString(); + return path.toString(); } -std::string cPictureCache::TranscodeUri(std::string uri, int width, int height) -{ - // We have to transform the uri a little... - // httpX://ServerUri/.../queryUri=localhost - - Poco::URI u(uri); - auto plServer = plexclient::plexgdm::GetInstance().GetServer(u.getHost(), u.getPort()); - u.setHost("127.0.0.1"); // set to localhost and http only! - u.setScheme("http"); - - Poco::URI serverUri(plServer->GetUri()); - serverUri.setPath("/photo/:/transcode"); - serverUri.addQueryParameter("width", std::to_string(width)); - serverUri.addQueryParameter("height", std::to_string(height)); - serverUri.addQueryParameter("url", u.toString()); - - return serverUri.toString(); +std::string cPictureCache::TranscodeUri(std::string uri, int width, int height) { + // We have to transform the uri a little... + // httpX://ServerUri/.../queryUri=localhost + + Poco::URI u(uri); + auto plServer = plexclient::plexgdm::GetInstance().GetServer(u.getHost(), u.getPort()); + u.setHost("127.0.0.1"); // set to localhost and http only! + u.setScheme("http"); + + Poco::URI serverUri(plServer->GetUri()); + serverUri.setPath("/photo/:/transcode"); + serverUri.addQueryParameter("width", std::to_string(width)); + serverUri.addQueryParameter("height", std::to_string(height)); + serverUri.addQueryParameter("url", u.toString()); + + return serverUri.toString(); } -bool cPictureCache::Cached(std::string uri, int width) -{ - bool cached = true; - try { - cached = m_mCached.at(FileName(uri, width)); - } catch (std::out_of_range) { } - - bool onDisk = Poco::File(FileName(uri, width) + ".jpg").exists() || Poco::File(FileName(uri, width) + ".png").exists(); - return onDisk && cached; +bool cPictureCache::Cached(std::string uri, int width) { + bool cached = true; + try { + cached = m_mCached.at(FileName(uri, width)); + } catch (std::out_of_range) { } + + bool onDisk = + Poco::File(FileName(uri, width) + ".jpg").exists() || Poco::File(FileName(uri, width) + ".png").exists(); + return onDisk && cached; } -std::string cPictureCache::GetPath(std::string uri, int width, int height, bool& cached, std::function<void(cGridElement*)> OnCached, cGridElement* calle) -{ - m_bAllInvalidated = false; - cached = Cached(uri, width); - std::string file = FileName(uri, width); - if(cached) { - if(Poco::File(FileName(uri, width) + ".jpg").exists()) { - file += ".jpg"; - } else if(Poco::File(FileName(uri, width) + ".png").exists()) { - file += ".png"; - } - return file; - } else { - - try { - m_mCached.at(file); - return file; - } catch (std::out_of_range) { } - - std::string transcodeUri = TranscodeUri(uri, width, height); - - m_mCached[file] = false; - - m_vFutures.push_back(std::async(std::launch::async, - [&] (std::string tsUri, std::string fn, std::function<void(cGridElement*)> onCached, cGridElement* ca) { - bool ok = DownloadFileAndSave(tsUri, fn); - if(ok) { - m_mCached[fn] = true; - } - if (ok && onCached && ca && ca->IsVisible()) { - onCached(ca); - } - return; - }, - transcodeUri, file, OnCached, calle) ); - } - - return file; +std::string cPictureCache::GetPath(std::string uri, int width, int height, bool &cached, + std::function<void(cGridElement *)> OnCached, cGridElement *calle) { + m_bAllInvalidated = false; + cached = Cached(uri, width); + std::string file = FileName(uri, width); + if (cached) { + if (Poco::File(FileName(uri, width) + ".jpg").exists()) { + file += ".jpg"; + } else if (Poco::File(FileName(uri, width) + ".png").exists()) { + file += ".png"; + } + return file; + } else { + + try { + m_mCached.at(file); + return file; + } catch (std::out_of_range) { } + + std::string transcodeUri = TranscodeUri(uri, width, height); + + m_mCached[file] = false; + + m_vFutures.push_back(std::async(std::launch::async, + [&](std::string tsUri, std::string fn, + std::function<void(cGridElement *)> onCached, cGridElement *ca) { + bool ok = DownloadFileAndSave(tsUri, fn); + if (ok) { + m_mCached[fn] = true; + } + if (ok && onCached && ca && ca->IsVisible()) { + onCached(ca); + } + return; + }, + transcodeUri, file, OnCached, calle)); + } + + return file; } diff --git a/pictureCache.h b/pictureCache.h index e259c6f..2cf1bd6 100644 --- a/pictureCache.h +++ b/pictureCache.h @@ -14,50 +14,55 @@ #include "viewGridNavigator.h" enum ImageResolution { - SD384, - SD480, - HD720, - HD1080 + SD384, + SD480, + HD720, + HD1080 }; -class cPictureCache -{ +class cPictureCache { private: - struct CacheInfo { - CacheInfo(std::string Uri, int Width, int Height, std::function<void(cGridElement*)> OnCached, cGridElement* Calle) { - uri = Uri; - width = Width; - height = Height; - onCached = OnCached; - calle = Calle; - }; - std::string uri; - int width; - int height; - std::function<void(cGridElement*)> onCached; - cGridElement* calle; - bool downloaded; - }; - cPictureCache(); - std::map<std::string, bool> m_mCached; - std::vector<std::future<void>> m_vFutures; - volatile bool m_bAllInvalidated; - - std::string FileName(std::string uri, int width); - std::string TranscodeUri(std::string uri, int width, int height); - - static bool DownloadFileAndSave(std::string uri, std::string localFile); - bool Cached(std::string uri, int width); - - std::string m_cacheDir; + struct CacheInfo { + CacheInfo(std::string Uri, int Width, int Height, std::function<void(cGridElement *)> OnCached, + cGridElement *Calle) { + uri = Uri; + width = Width; + height = Height; + onCached = OnCached; + calle = Calle; + }; + std::string uri; + int width; + int height; + std::function<void(cGridElement *)> onCached; + cGridElement *calle; + bool downloaded; + }; + + cPictureCache(); + + std::map<std::string, bool> m_mCached; + std::vector<std::future<void>> m_vFutures; + volatile bool m_bAllInvalidated; + + std::string FileName(std::string uri, int width); + + std::string TranscodeUri(std::string uri, int width, int height); + + static bool DownloadFileAndSave(std::string uri, std::string localFile); + + bool Cached(std::string uri, int width); + + std::string m_cacheDir; public: - static cPictureCache& GetInstance() { - static cPictureCache instance; - return instance; - } + static cPictureCache &GetInstance() { + static cPictureCache instance; + return instance; + } - std::string GetPath(std::string uri, int width, int height, bool& cached, std::function<void(cGridElement*)> OnCached = NULL, cGridElement* calle = NULL); + std::string GetPath(std::string uri, int width, int height, bool &cached, + std::function<void(cGridElement *)> OnCached = NULL, cGridElement *calle = NULL); }; #endif // CPICTURECACHE_H diff --git a/playlist.cpp b/playlist.cpp index 4162591..772e14d 100644 --- a/playlist.cpp +++ b/playlist.cpp @@ -1,11 +1,9 @@ #include "playlist.h" -namespace plexclient -{ +namespace plexclient { -Playlist::Playlist(Poco::XML::Node* pNode, MediaContainer* parent) -{ -} + Playlist::Playlist(Poco::XML::Node *pNode, MediaContainer *parent) { + } } @@ -4,15 +4,13 @@ #include "XmlObject.h" // Base class: plexclient::XmlObject #include "MediaContainer.h" -namespace plexclient -{ +namespace plexclient { -class Playlist : private plexclient::XmlObject -{ -public: - Playlist(Poco::XML::Node* pNode, MediaContainer* parent); + class Playlist : private plexclient::XmlObject { + public: + Playlist(Poco::XML::Node *pNode, MediaContainer *parent); -}; + }; } @@ -30,17 +30,15 @@ bool cMyPlugin::PlayingFile = false; ** @note DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL ** VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! */ -cMyPlugin::cMyPlugin(void) -{ +cMyPlugin::cMyPlugin(void) { } /** ** Clean up after yourself! */ -cMyPlugin::~cMyPlugin(void) -{ - plexclient::plexgdm::GetInstance().stopRegistration(); - plexclient::ControlServer::GetInstance().Stop(); +cMyPlugin::~cMyPlugin(void) { + plexclient::plexgdm::GetInstance().stopRegistration(); + plexclient::ControlServer::GetInstance().Stop(); } /** @@ -48,9 +46,8 @@ cMyPlugin::~cMyPlugin(void) ** ** @returns version number as constant string. */ -const char *cMyPlugin::Version(void) -{ - return VERSION; +const char *cMyPlugin::Version(void) { + return VERSION; } /** @@ -58,153 +55,158 @@ const char *cMyPlugin::Version(void) ** ** @returns short description as constant string. */ -const char *cMyPlugin::Description(void) -{ - return DESCRIPTION; +const char *cMyPlugin::Description(void) { + return DESCRIPTION; } -bool cMyPlugin::Start(void) -{ +bool cMyPlugin::Start(void) { #ifdef SKINDESIGNER - m_pPlugStruct = new skindesignerapi::cPluginStructure(); - m_pPlugStruct->name = "plex"; - m_pPlugStruct->libskindesignerAPIVersion = LIBSKINDESIGNERAPIVERSION; - - m_pPlugStruct->RegisterRootView("root.xml"); - skindesignerapi::cTokenContainer *tkBackground = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineTokens(eViewElementsRoot::background, tkBackground); - m_pPlugStruct->RegisterViewElement((int)eViews::rootView, (int)eViewElementsRoot::background, "background", tkBackground); - - skindesignerapi::cTokenContainer *tkHeader = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineTokens(eViewElementsRoot::header, tkHeader); - m_pPlugStruct->RegisterViewElement((int)eViews::rootView, (int)eViewElementsRoot::header, "header", tkHeader); - - skindesignerapi::cTokenContainer *tkFooter = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineTokens(eViewElementsRoot::footer, tkFooter); - m_pPlugStruct->RegisterViewElement((int)eViews::rootView, (int)eViewElementsRoot::footer, "footer", tkFooter); - - skindesignerapi::cTokenContainer *tkInfopane = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineTokens(eViewElementsRoot::infopane, tkInfopane); - m_pPlugStruct->RegisterViewElement((int)eViews::rootView, (int)eViewElementsRoot::infopane, "infopane", tkInfopane); - - skindesignerapi::cTokenContainer *tkWatch = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineTokens(eViewElementsRoot::watch, tkWatch); - m_pPlugStruct->RegisterViewElement((int)eViews::rootView, (int)eViewElementsRoot::watch, "time", tkWatch); - - skindesignerapi::cTokenContainer *tkMessage = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineTokens(eViewElementsRoot::message, tkMessage); - m_pPlugStruct->RegisterViewElement((int)eViews::rootView, (int)eViewElementsRoot::message, "message", tkMessage); - - skindesignerapi::cTokenContainer *tkScrollbar = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineTokens(eViewElementsRoot::scrollbar, tkScrollbar); - m_pPlugStruct->RegisterViewElement((int)eViews::rootView, (int)eViewElementsRoot::scrollbar, "scrollbar", tkScrollbar); - - skindesignerapi::cTokenContainer *tkGridCover = new skindesignerapi::cTokenContainer(); - skindesignerapi::cTokenContainer *tkGridDetail = new skindesignerapi::cTokenContainer(); - skindesignerapi::cTokenContainer *tkGridList = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineGridTokens(tkGridCover); - cPlexSdOsd::DefineGridTokens(tkGridDetail); - cPlexSdOsd::DefineGridTokens(tkGridList); - m_pPlugStruct->RegisterViewGrid((int)eViews::rootView, (int)eViewGrids::cover, "coverbrowser", tkGridCover); - m_pPlugStruct->RegisterViewGrid((int)eViews::rootView, (int)eViewGrids::detail, "detailbrowser", tkGridDetail); - m_pPlugStruct->RegisterViewGrid((int)eViews::rootView, (int)eViewGrids::list, "listbrowser", tkGridList); - - // DetailsView - m_pPlugStruct->RegisterSubView((int)eViews::detailView, "detail.xml"); - skindesignerapi::cTokenContainer *tkBackgroundDetail = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::background, tkBackgroundDetail); - m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::background, "background", tkBackgroundDetail); - - skindesignerapi::cTokenContainer *tkDetailInfo = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::info, tkDetailInfo); - m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::info, "info", tkDetailInfo); - - skindesignerapi::cTokenContainer *tkDetailFooter = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::footer, tkDetailFooter); - m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::footer, "footer", tkDetailFooter); - - skindesignerapi::cTokenContainer *tkDetailScrollbar = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::scrollbar, tkDetailScrollbar); - m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::scrollbar, "scrollbar", tkDetailScrollbar); - - skindesignerapi::cTokenContainer *tkDetailMessage = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::message, tkDetailMessage); - m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::message, "message", tkDetailMessage); - - skindesignerapi::cTokenContainer *tkDetailExtraGrid = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineGridTokens(tkDetailExtraGrid); - m_pPlugStruct->RegisterViewGrid((int)eViews::detailView, (int)eViewDetailViewGrids::extras, "extragrid", tkDetailExtraGrid); - - skindesignerapi::cTokenContainer *tkDetailWatch = new skindesignerapi::cTokenContainer(); - cPlexSdOsd::DefineWatchTokens(tkDetailWatch); - m_pPlugStruct->RegisterViewElement((int)eViews::detailView, (int)eViewElementsDetail::watch, "time", tkDetailWatch); - - - if (!skindesignerapi::SkindesignerAPI::RegisterPlugin(m_pPlugStruct)) { - esyslog("[plex]: skindesigner not available"); - bSkindesigner = false; - } else { - dsyslog("[plex]: successfully registered at skindesigner, id %d", m_pPlugStruct->id); - m_pTestOsd = new cPlexSdOsd(m_pPlugStruct); - bSkindesigner = true; - } + m_pPlugStruct = new skindesignerapi::cPluginStructure(); + m_pPlugStruct->name = "plex"; + m_pPlugStruct->libskindesignerAPIVersion = LIBSKINDESIGNERAPIVERSION; + + m_pPlugStruct->RegisterRootView("root.xml"); + skindesignerapi::cTokenContainer *tkBackground = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineTokens(eViewElementsRoot::background, tkBackground); + m_pPlugStruct->RegisterViewElement((int) eViews::rootView, (int) eViewElementsRoot::background, "background", + tkBackground); + + skindesignerapi::cTokenContainer *tkHeader = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineTokens(eViewElementsRoot::header, tkHeader); + m_pPlugStruct->RegisterViewElement((int) eViews::rootView, (int) eViewElementsRoot::header, "header", tkHeader); + + skindesignerapi::cTokenContainer *tkFooter = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineTokens(eViewElementsRoot::footer, tkFooter); + m_pPlugStruct->RegisterViewElement((int) eViews::rootView, (int) eViewElementsRoot::footer, "footer", tkFooter); + + skindesignerapi::cTokenContainer *tkInfopane = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineTokens(eViewElementsRoot::infopane, tkInfopane); + m_pPlugStruct->RegisterViewElement((int) eViews::rootView, (int) eViewElementsRoot::infopane, "infopane", + tkInfopane); + + skindesignerapi::cTokenContainer *tkWatch = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineTokens(eViewElementsRoot::watch, tkWatch); + m_pPlugStruct->RegisterViewElement((int) eViews::rootView, (int) eViewElementsRoot::watch, "time", tkWatch); + + skindesignerapi::cTokenContainer *tkMessage = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineTokens(eViewElementsRoot::message, tkMessage); + m_pPlugStruct->RegisterViewElement((int) eViews::rootView, (int) eViewElementsRoot::message, "message", tkMessage); + + skindesignerapi::cTokenContainer *tkScrollbar = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineTokens(eViewElementsRoot::scrollbar, tkScrollbar); + m_pPlugStruct->RegisterViewElement((int) eViews::rootView, (int) eViewElementsRoot::scrollbar, "scrollbar", + tkScrollbar); + + skindesignerapi::cTokenContainer *tkGridCover = new skindesignerapi::cTokenContainer(); + skindesignerapi::cTokenContainer *tkGridDetail = new skindesignerapi::cTokenContainer(); + skindesignerapi::cTokenContainer *tkGridList = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineGridTokens(tkGridCover); + cPlexSdOsd::DefineGridTokens(tkGridDetail); + cPlexSdOsd::DefineGridTokens(tkGridList); + m_pPlugStruct->RegisterViewGrid((int) eViews::rootView, (int) eViewGrids::cover, "coverbrowser", tkGridCover); + m_pPlugStruct->RegisterViewGrid((int) eViews::rootView, (int) eViewGrids::detail, "detailbrowser", tkGridDetail); + m_pPlugStruct->RegisterViewGrid((int) eViews::rootView, (int) eViewGrids::list, "listbrowser", tkGridList); + + // DetailsView + m_pPlugStruct->RegisterSubView((int) eViews::detailView, "detail.xml"); + skindesignerapi::cTokenContainer *tkBackgroundDetail = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::background, tkBackgroundDetail); + m_pPlugStruct->RegisterViewElement((int) eViews::detailView, (int) eViewElementsDetail::background, "background", + tkBackgroundDetail); + + skindesignerapi::cTokenContainer *tkDetailInfo = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::info, tkDetailInfo); + m_pPlugStruct->RegisterViewElement((int) eViews::detailView, (int) eViewElementsDetail::info, "info", tkDetailInfo); + + skindesignerapi::cTokenContainer *tkDetailFooter = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::footer, tkDetailFooter); + m_pPlugStruct->RegisterViewElement((int) eViews::detailView, (int) eViewElementsDetail::footer, "footer", + tkDetailFooter); + + skindesignerapi::cTokenContainer *tkDetailScrollbar = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::scrollbar, tkDetailScrollbar); + m_pPlugStruct->RegisterViewElement((int) eViews::detailView, (int) eViewElementsDetail::scrollbar, "scrollbar", + tkDetailScrollbar); + + skindesignerapi::cTokenContainer *tkDetailMessage = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail::message, tkDetailMessage); + m_pPlugStruct->RegisterViewElement((int) eViews::detailView, (int) eViewElementsDetail::message, "message", + tkDetailMessage); + + skindesignerapi::cTokenContainer *tkDetailExtraGrid = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineGridTokens(tkDetailExtraGrid); + m_pPlugStruct->RegisterViewGrid((int) eViews::detailView, (int) eViewDetailViewGrids::extras, "extragrid", + tkDetailExtraGrid); + + skindesignerapi::cTokenContainer *tkDetailWatch = new skindesignerapi::cTokenContainer(); + cPlexSdOsd::DefineWatchTokens(tkDetailWatch); + m_pPlugStruct->RegisterViewElement((int) eViews::detailView, (int) eViewElementsDetail::watch, "time", + tkDetailWatch); + + + if (!skindesignerapi::SkindesignerAPI::RegisterPlugin(m_pPlugStruct)) { + esyslog("[plex]: skindesigner not available"); + bSkindesigner = false; + } else { + dsyslog("[plex]: successfully registered at skindesigner, id %d", m_pPlugStruct->id); + m_pTestOsd = new cPlexSdOsd(m_pPlugStruct); + bSkindesigner = true; + } #endif - return true; + return true; } /** ** Start any background activities the plugin shall perform. */ -bool cMyPlugin::Initialize(void) -{ - // Initialize SSL - { - using namespace Poco; - using namespace Poco::Net; - using Poco::Net::SSLManager; - using Poco::Net::Context; - using Poco::Net::AcceptCertificateHandler; - using Poco::Net::PrivateKeyPassphraseHandler; - using Poco::Net::InvalidCertificateHandler; - using Poco::Net::ConsoleCertificateHandler; - - //SharedPtr<PrivateKeyPassphraseHandler> pConsoleHandler = new PrivateKeyPassphraseHandler; - SharedPtr<InvalidCertificateHandler> pInvalidCertHandler = new AcceptCertificateHandler(false); - Context::Ptr pContext = new Poco::Net::Context( - Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE, // VERIFY_NONE...?! - 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); - SSLManager::instance().initializeClient(NULL, pInvalidCertHandler, pContext); - } - // First Startup? Save UUID - SetupStore("UUID", Config::GetInstance().GetUUID().c_str()); - - plexclient::plexgdm::GetInstance().clientDetails(Config::GetInstance().GetUUID(), Config::GetInstance().GetHostname(), "3200", DESCRIPTION, VERSION); - plexclient::plexgdm::GetInstance().Start(); - plexclient::ControlServer::GetInstance().Start(); - - return true; +bool cMyPlugin::Initialize(void) { + // Initialize SSL + { + using namespace Poco; + using namespace Poco::Net; + using Poco::Net::SSLManager; + using Poco::Net::Context; + using Poco::Net::AcceptCertificateHandler; + using Poco::Net::PrivateKeyPassphraseHandler; + using Poco::Net::InvalidCertificateHandler; + using Poco::Net::ConsoleCertificateHandler; + + //SharedPtr<PrivateKeyPassphraseHandler> pConsoleHandler = new PrivateKeyPassphraseHandler; + SharedPtr<InvalidCertificateHandler> pInvalidCertHandler = new AcceptCertificateHandler(false); + Context::Ptr pContext = new Poco::Net::Context( + Context::CLIENT_USE, "", "", "", Context::VERIFY_NONE, // VERIFY_NONE...?! + 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); + SSLManager::instance().initializeClient(NULL, pInvalidCertHandler, pContext); + } + // First Startup? Save UUID + SetupStore("UUID", Config::GetInstance().GetUUID().c_str()); + + plexclient::plexgdm::GetInstance().clientDetails(Config::GetInstance().GetUUID(), + Config::GetInstance().GetHostname(), "3200", DESCRIPTION, VERSION); + plexclient::plexgdm::GetInstance().Start(); + plexclient::ControlServer::GetInstance().Start(); + + return true; } /** ** Create main menu entry. */ -const char *cMyPlugin::MainMenuEntry(void) -{ - return Config::GetInstance().HideMainMenuEntry ? NULL : MAINMENUENTRY; +const char *cMyPlugin::MainMenuEntry(void) { + return Config::GetInstance().HideMainMenuEntry ? NULL : MAINMENUENTRY; } /** ** Perform the action when selected from the main VDR menu. */ -cOsdObject *cMyPlugin::MainMenuAction(void) -{ - //dsyslog("[plex]%s:\n", __FUNCTION__); +cOsdObject *cMyPlugin::MainMenuAction(void) { + //dsyslog("[plex]%s:\n", __FUNCTION__); #ifdef SKINDESIGNER - if(bSkindesigner && m_pTestOsd->SdSupport()) return new cPlexSdOsd(m_pPlugStruct); - else return cPlexMenu::ProcessMenu(); + if (bSkindesigner && m_pTestOsd->SdSupport()) return new cPlexSdOsd(m_pPlugStruct); + else return cPlexMenu::ProcessMenu(); #else - return cPlexMenu::ProcessMenu(); + return cPlexMenu::ProcessMenu(); #endif } @@ -212,23 +214,21 @@ cOsdObject *cMyPlugin::MainMenuAction(void) ** Called for every plugin once during every cycle of VDR's main program ** loop. */ -void cMyPlugin::MainThreadHook(void) -{ - // dsyslog("[plex]%s:\n", __FUNCTION__); - // Start Tasks, e.g. Play Video - if(plexclient::ActionManager::GetInstance().IsAction()) { - PlayFile(plexclient::ActionManager::GetInstance().GetAction()); - } +void cMyPlugin::MainThreadHook(void) { + // dsyslog("[plex]%s:\n", __FUNCTION__); + // Start Tasks, e.g. Play Video + if (plexclient::ActionManager::GetInstance().IsAction()) { + PlayFile(plexclient::ActionManager::GetInstance().GetAction()); + } } /** ** Return our setup menu. */ -cMenuSetupPage *cMyPlugin::SetupMenu(void) -{ - //dsyslog("[plex]%s:\n", __FUNCTION__); +cMenuSetupPage *cMyPlugin::SetupMenu(void) { + //dsyslog("[plex]%s:\n", __FUNCTION__); - return new cMyMenuSetupPage; + return new cMyMenuSetupPage; } /** @@ -239,11 +239,10 @@ cMenuSetupPage *cMyPlugin::SetupMenu(void) ** ** @returns true if the parameter is supported. */ -bool cMyPlugin::SetupParse(const char *name, const char *value) -{ - //dsyslog("[plex]%s: '%s' = '%s'\n", __FUNCTION__, name, value); +bool cMyPlugin::SetupParse(const char *name, const char *value) { + //dsyslog("[plex]%s: '%s' = '%s'\n", __FUNCTION__, name, value); - return Config::GetInstance().Parse(name, value); + return Config::GetInstance().Parse(name, value); } /** @@ -251,56 +250,55 @@ bool cMyPlugin::SetupParse(const char *name, const char *value) ** ** @param filename path and file name */ -void cMyPlugin::PlayFile(plexclient::cVideo Vid) -{ - if(Vid.m_iMyPlayOffset == 0 && Vid.m_lViewoffset > 0 ) { - cString message = cString::sprintf(tr("To start from %ld minutes, press Ok."), Vid.m_lViewoffset / 60000); - eKeys response = Skins.Message(eMessageType::mtInfo, message, 5); - if(response == kOk) { - Vid.m_iMyPlayOffset = Vid.m_lViewoffset/1000; - } - } - - cPlugin* mpvPlugin = cPluginManager::GetPlugin("mpv"); - - if(Config::GetInstance().UseMpv && mpvPlugin) { - CurrentVideo = Vid; - cMyPlugin::PlayingFile = true; - - Mpv_PlayFile req; - Mpv_SetTitle reqTitle; - std::string file; - if(Config::GetInstance().UsePlexAccount && Vid.m_pServer->IsLocal() == false) { - file = plexclient::Plexservice::GetUniversalTranscodeUrl(&Vid, Vid.m_iMyPlayOffset, NULL, true); - } - else { - file = (Vid.m_pServer->GetUri() + Vid.m_Media.m_sPartKey); - } - - req.Filename = (char*)file.c_str(); - mpvPlugin->Service(MPV_PLAY_FILE, &req); - - reqTitle.Title = (char*)Vid.GetTitle().c_str(); - mpvPlugin->Service(MPV_SET_TITLE, &reqTitle); - - // Set "StartAt" for mpv player - Mpv_Seek seekData; - seekData.SeekAbsolute = Vid.m_iMyPlayOffset; - seekData.SeekRelative = 0; - mpvPlugin->Service(MPV_SEEK, &seekData); - - return; - - } else if (Config::GetInstance().UseMpv) { - isyslog("Can't find mpv %s, playing directly.", mpvPlugin ? "service" : "plugin"); - } - - - isyslog("[plex]: play file '%s'\n", Vid.m_sKey.c_str()); - cControl* control = cHlsPlayerControl::Create(Vid); - if(control) { - cControl::Launch(control); - } +void cMyPlugin::PlayFile(plexclient::cVideo Vid) { + if (Vid.m_iMyPlayOffset == 0 && Vid.m_lViewoffset > 0) { + cString message = cString::sprintf(tr("To start from %ld minutes, press Ok."), Vid.m_lViewoffset / 60000); + eKeys response = Skins.Message(eMessageType::mtInfo, message, 5); + if (response == kOk) { + Vid.m_iMyPlayOffset = Vid.m_lViewoffset / 1000; + } + } + + cPlugin *mpvPlugin = cPluginManager::GetPlugin("mpv"); + + if (Config::GetInstance().UseMpv && mpvPlugin) { + CurrentVideo = Vid; + cMyPlugin::PlayingFile = true; + + Mpv_PlayFile req; + Mpv_SetTitle reqTitle; + std::string file; + if (Config::GetInstance().UsePlexAccount && Vid.m_pServer->IsLocal() == false) { + file = plexclient::Plexservice::GetUniversalTranscodeUrl(&Vid, Vid.m_iMyPlayOffset, NULL, true); + } + else { + file = (Vid.m_pServer->GetUri() + Vid.m_Media.m_sPartKey); + } + + req.Filename = (char *) file.c_str(); + mpvPlugin->Service(MPV_PLAY_FILE, &req); + + reqTitle.Title = (char *) Vid.GetTitle().c_str(); + mpvPlugin->Service(MPV_SET_TITLE, &reqTitle); + + // Set "StartAt" for mpv player + Mpv_Seek seekData; + seekData.SeekAbsolute = Vid.m_iMyPlayOffset; + seekData.SeekRelative = 0; + mpvPlugin->Service(MPV_SEEK, &seekData); + + return; + + } else if (Config::GetInstance().UseMpv) { + isyslog("Can't find mpv %s, playing directly.", mpvPlugin ? "service" : "plugin"); + } + + + isyslog("[plex]: play file '%s'\n", Vid.m_sKey.c_str()); + cControl *control = cHlsPlayerControl::Create(Vid); + if (control) { + cControl::Launch(control); + } } -VDRPLUGINCREATOR(cMyPlugin); // Don't touch this! +VDRPLUGINCREATOR(cMyPlugin); // Don't touch this! @@ -18,9 +18,11 @@ #include "hlsPlayerControl.h" #ifdef SKINDESIGNER - #include <libskindesignerapi/skindesignerapi.h> - #include "plexSdOsd.h" - #include "pictureCache.h" + +#include <libskindesignerapi/skindesignerapi.h> +#include "plexSdOsd.h" +#include "pictureCache.h" + #endif #include <iostream> @@ -35,41 +37,52 @@ /// for the distribution archive. static const char *const VERSION = "0.3.0" #ifdef GIT_REV - "-GIT" GIT_REV +"-GIT" GIT_REV #endif - ; +; static const char *const DESCRIPTION = "Plex for VDR Plugin"; static const char *const MAINMENUENTRY = "Plex for VDR"; -class cMyPlugin:public cPlugin -{ +class cMyPlugin : public cPlugin { private: #ifdef SKINDESIGNER - skindesignerapi::cPluginStructure *m_pPlugStruct; - cPlexSdOsd *m_pTestOsd; - static bool bSkindesigner; + skindesignerapi::cPluginStructure *m_pPlugStruct; + cPlexSdOsd *m_pTestOsd; + static bool bSkindesigner; #endif - + public: - cMyPlugin(void); - virtual ~ cMyPlugin(void); - virtual const char *Version(void); - virtual const char *Description(void); - virtual bool Initialize(void); - virtual bool Start(void); - virtual void MainThreadHook(void); - virtual const char *MainMenuEntry(void); - virtual cOsdObject *MainMenuAction(void); - virtual cMenuSetupPage *SetupMenu(void); - virtual bool SetupParse(const char *, const char *); - - static plexclient::cVideo CurrentVideo; - static bool PlayingFile; - static void PlayFile(plexclient::cVideo Vid); + cMyPlugin(void); + + virtual ~ cMyPlugin(void); + + virtual const char *Version(void); + + virtual const char *Description(void); + + virtual bool Initialize(void); + + virtual bool Start(void); + + virtual void MainThreadHook(void); + + virtual const char *MainMenuEntry(void); + + virtual cOsdObject *MainMenuAction(void); + + virtual cMenuSetupPage *SetupMenu(void); + + virtual bool SetupParse(const char *, const char *); + + static plexclient::cVideo CurrentVideo; + static bool PlayingFile; + + static void PlayFile(plexclient::cVideo Vid); public: - static volatile bool CalledFromCode; + static volatile bool CalledFromCode; }; + #endif diff --git a/plexOsd.cpp b/plexOsd.cpp index 0d89041..13cb86e 100644 --- a/plexOsd.cpp +++ b/plexOsd.cpp @@ -9,158 +9,154 @@ static std::shared_ptr<plexclient::Plexservice> pPlexService; std::shared_ptr<plexclient::Plexservice> cPlexBrowser::pLastService; int cPlexBrowser::lastCurrentItem; -cPlexBrowser::cPlexBrowser(const char *title, std::shared_ptr<plexclient::Plexservice> Service) :cOsdMenu(title) -{ - dsyslog("[plex]%s:\n", __FUNCTION__); - pService = Service; - //pService->Authenticate(); - if(pService == pLastService) { - pCont = pService->GetLastSection(true); - } else { - pCont = pService->GetSection(pService->StartUri); - } - SetMenuCategory(mcRecording); - CreateMenu(); +cPlexBrowser::cPlexBrowser(const char *title, std::shared_ptr<plexclient::Plexservice> Service) : cOsdMenu(title) { + dsyslog("[plex]%s:\n", __FUNCTION__); + pService = Service; + //pService->Authenticate(); + if (pService == pLastService) { + pCont = pService->GetLastSection(true); + } else { + pCont = pService->GetSection(pService->StartUri); + } + SetMenuCategory(mcRecording); + CreateMenu(); } -cPlexBrowser* cPlexBrowser::RecoverLastState() -{ - if (cPlexBrowser::pLastService != NULL) { - cPlexBrowser* pBrowser = new cPlexBrowser("", cPlexBrowser::pLastService); - return pBrowser; - } - return NULL; +cPlexBrowser *cPlexBrowser::RecoverLastState() { + if (cPlexBrowser::pLastService != NULL) { + cPlexBrowser *pBrowser = new cPlexBrowser("", cPlexBrowser::pLastService); + return pBrowser; + } + return NULL; } -void cPlexBrowser::CreateMenu() -{ - // Clear Menu - Clear(); - // Directory or Video? - if(pCont && pCont->m_vDirectories.size() > 0) { - - for(std::vector<plexclient::Directory>::iterator it = pCont->m_vDirectories.begin(); it != pCont->m_vDirectories.end(); ++it) { - plexclient::Directory *pDir = &(*it); - Add(new cPlexOsdItem( tr(pDir->GetTitle().c_str()), pDir) ); - } - } - - if(pCont && pCont->m_vVideos.size() > 0) { - for(std::vector<plexclient::cVideo>::iterator it = pCont->m_vVideos.begin(); it != pCont->m_vVideos.end(); ++it) { - plexclient::cVideo *vid = &(*it); // cast raw pointer - Add(new cPlexOsdItem( vid->GetTitle().c_str(), vid) ); - } - } - - if(Count() < 1) { - Add(new cPlexOsdItem("Empty")); - } else if (pService == pLastService) { - // recover last selected item - cOsdItem* item = Get(lastCurrentItem); - SetCurrent(item); - pLastService = NULL; - } - - Display(); +void cPlexBrowser::CreateMenu() { + // Clear Menu + Clear(); + // Directory or Video? + if (pCont && pCont->m_vDirectories.size() > 0) { + + for (std::vector<plexclient::Directory>::iterator it = pCont->m_vDirectories.begin(); + it != pCont->m_vDirectories.end(); ++it) { + plexclient::Directory *pDir = &(*it); + Add(new cPlexOsdItem(tr(pDir->GetTitle().c_str()), pDir)); + } + } + + if (pCont && pCont->m_vVideos.size() > 0) { + for (std::vector<plexclient::cVideo>::iterator it = pCont->m_vVideos.begin(); + it != pCont->m_vVideos.end(); ++it) { + plexclient::cVideo *vid = &(*it); // cast raw pointer + Add(new cPlexOsdItem(vid->GetTitle().c_str(), vid)); + } + } + + if (Count() < 1) { + Add(new cPlexOsdItem("Empty")); + } else if (pService == pLastService) { + // recover last selected item + cOsdItem *item = Get(lastCurrentItem); + SetCurrent(item); + pLastService = NULL; + } + + Display(); } -eOSState cPlexBrowser::ProcessKey(eKeys key) -{ - eOSState state; - - // call standard function - state = cOsdMenu::ProcessKey(key); - - int current = Current(); // get current menu item index - cPlexOsdItem *item = static_cast<cPlexOsdItem*>(Get(current)); - - if(item->IsVideo()) { - if(item->GetAttachedVideo()->m_iViewCount > 0) SetHelp(tr("Info"), tr("Unscrobble")); - else SetHelp(tr("Info"), tr("Scrobble")); - } else { - SetHelp(NULL); - } - - switch (state) { - case osUnknown: - switch (key) { - case kOk: - return ProcessSelected(); - case kBack: - return LevelUp(); - case kRed: - if(item->IsVideo()) { - std::cout << " Video Info"; - } - std::cout << std::endl; - break; - case kGreen: - if(item->IsVideo()) { - if(item->GetAttachedVideo()->m_iViewCount > 0) { - if(item->GetAttachedVideo()->SetUnwatched()) { - item->GetAttachedVideo()->UpdateFromServer(); - } - } else { - if(item->GetAttachedVideo()->SetWatched()) { - item->GetAttachedVideo()->UpdateFromServer(); - } - } - } - if(item->GetAttachedVideo()->m_iViewCount > 0) SetHelp(tr("Info"), tr("Unscrobble")); - else SetHelp(tr("Info"), tr("Scrobble")); - break; - default: - break; - } - break; - case osBack: - state = LevelUp(); - if (state == osEnd) { // top level reached - return osPlugin; - } - default: - break; - } - return state; +eOSState cPlexBrowser::ProcessKey(eKeys key) { + eOSState state; + + // call standard function + state = cOsdMenu::ProcessKey(key); + + int current = Current(); // get current menu item index + cPlexOsdItem *item = static_cast<cPlexOsdItem *>(Get(current)); + + if (item->IsVideo()) { + if (item->GetAttachedVideo()->m_iViewCount > 0) SetHelp(tr("Info"), tr("Unscrobble")); + else SetHelp(tr("Info"), tr("Scrobble")); + } else { + SetHelp(NULL); + } + + switch (state) { + case osUnknown: + switch (key) { + case kOk: + return ProcessSelected(); + case kBack: + return LevelUp(); + case kRed: + if (item->IsVideo()) { + std::cout << " Video Info"; + } + std::cout << std::endl; + break; + case kGreen: + if (item->IsVideo()) { + if (item->GetAttachedVideo()->m_iViewCount > 0) { + if (item->GetAttachedVideo()->SetUnwatched()) { + item->GetAttachedVideo()->UpdateFromServer(); + } + } else { + if (item->GetAttachedVideo()->SetWatched()) { + item->GetAttachedVideo()->UpdateFromServer(); + } + } + } + if (item->GetAttachedVideo()->m_iViewCount > 0) SetHelp(tr("Info"), tr("Unscrobble")); + else SetHelp(tr("Info"), tr("Scrobble")); + break; + default: + break; + } + break; + case osBack: + state = LevelUp(); + if (state == osEnd) { // top level reached + return osPlugin; + } + default: + break; + } + return state; } -eOSState cPlexBrowser::LevelUp() -{ - pCont = pService->GetLastSection(); - if(!pCont) { - cPlexMenu::eShow = menuShow::MAIN; - return osEnd; - } - cString title = cString::sprintf(tr("Browse Plex - %s"), tr(pCont->m_sTitle1.c_str())); - SetTitle(title); - CreateMenu(); - return osContinue; +eOSState cPlexBrowser::LevelUp() { + pCont = pService->GetLastSection(); + if (!pCont) { + cPlexMenu::eShow = menuShow::MAIN; + return osEnd; + } + cString title = cString::sprintf(tr("Browse Plex - %s"), tr(pCont->m_sTitle1.c_str())); + SetTitle(title); + CreateMenu(); + return osContinue; } -eOSState cPlexBrowser::ProcessSelected() -{ - int current = Current(); // get current menu item index - cPlexOsdItem *item = static_cast<cPlexOsdItem*>(Get(current)); - - - if(item->IsVideo()) { - pLastService = pService; - lastCurrentItem = current; - cMyPlugin::PlayFile(*item->GetAttachedVideo()); - return osEnd; - } - - if(item->IsDir()) { - plexclient::Directory* pDir = item->GetAttachedDirectory(); - pCont = pService->GetSection(pDir->m_sKey); - cString title = cString::sprintf(tr("Browse Plex - %s"), tr(pDir->m_sTitle.c_str())); - SetTitle(title); - CreateMenu(); - return osContinue; - } - - //return osEnd; - return osContinue; +eOSState cPlexBrowser::ProcessSelected() { + int current = Current(); // get current menu item index + cPlexOsdItem *item = static_cast<cPlexOsdItem *>(Get(current)); + + + if (item->IsVideo()) { + pLastService = pService; + lastCurrentItem = current; + cMyPlugin::PlayFile(*item->GetAttachedVideo()); + return osEnd; + } + + if (item->IsDir()) { + plexclient::Directory *pDir = item->GetAttachedDirectory(); + pCont = pService->GetSection(pDir->m_sKey); + cString title = cString::sprintf(tr("Browse Plex - %s"), tr(pDir->m_sTitle.c_str())); + SetTitle(title); + CreateMenu(); + return osContinue; + } + + //return osEnd; + return osContinue; } @@ -174,40 +170,41 @@ menuShow cPlexMenu::eShow = MAIN; ** Plex menu constructor. */ cPlexMenu::cPlexMenu(const char *title, int c0, int c1, int c2, int c3, int c4) - :cOsdMenu(title) -{ - SetHasHotkeys(); - - for(std::vector<plexclient::PlexServer>::iterator it = plexclient::plexgdm::GetInstance().GetPlexservers().begin(); it != plexclient::plexgdm::GetInstance().GetPlexservers().end(); ++it) { - for(std::vector<ViewEntry>::iterator vEntry = Config::GetInstance().m_serverViewentries.begin(); vEntry != Config::GetInstance().m_serverViewentries.end(); ++vEntry) { - auto plexService = std::make_shared<plexclient::Plexservice>( &(*it) ); - plexService->StartUri = vEntry->PlexPath; - Add(new cPlexOsdItem(Poco::format("%s - %s", it->GetServerName(), vEntry->Name ).c_str(), plexService )); - } - for(std::vector<ViewEntry>::iterator vEntry = Config::GetInstance().m_viewentries.begin(); vEntry != Config::GetInstance().m_viewentries.end(); ++vEntry) { - auto plexService = std::make_shared<plexclient::Plexservice>( &(*it) ); - plexService->StartUri = vEntry->PlexPath; - Add(new cPlexOsdItem(Poco::format("%s - %s", it->GetServerName(), vEntry->Name ).c_str(), plexService )); - } - } - - - if(Count() < 1) { - Add(new cPlexOsdItem(tr("No Plex Media Server found.")), false); - } + : cOsdMenu(title) { + SetHasHotkeys(); + + for (std::vector<plexclient::PlexServer>::iterator it = plexclient::plexgdm::GetInstance().GetPlexservers().begin(); + it != plexclient::plexgdm::GetInstance().GetPlexservers().end(); ++it) { + for (std::vector<ViewEntry>::iterator vEntry = Config::GetInstance().m_serverViewentries.begin(); + vEntry != Config::GetInstance().m_serverViewentries.end(); ++vEntry) { + auto plexService = std::make_shared<plexclient::Plexservice>(&(*it)); + plexService->StartUri = vEntry->PlexPath; + Add(new cPlexOsdItem(Poco::format("%s - %s", it->GetServerName(), vEntry->Name).c_str(), plexService)); + } + for (std::vector<ViewEntry>::iterator vEntry = Config::GetInstance().m_viewentries.begin(); + vEntry != Config::GetInstance().m_viewentries.end(); ++vEntry) { + auto plexService = std::make_shared<plexclient::Plexservice>(&(*it)); + plexService->StartUri = vEntry->PlexPath; + Add(new cPlexOsdItem(Poco::format("%s - %s", it->GetServerName(), vEntry->Name).c_str(), plexService)); + } + } + + + if (Count() < 1) { + Add(new cPlexOsdItem(tr("No Plex Media Server found.")), false); + } } -cOsdMenu* cPlexMenu::ProcessMenu() -{ - if(cMyPlugin::CalledFromCode) { - cMyPlugin::CalledFromCode = false; - return cPlexBrowser::RecoverLastState(); - } - - if (cPlexMenu::eShow == menuShow::BROWSER) { - return new cPlexBrowser(tr("Browse Plex"), pPlexService); - } - return new cPlexMenu("Plex"); +cOsdMenu *cPlexMenu::ProcessMenu() { + if (cMyPlugin::CalledFromCode) { + cMyPlugin::CalledFromCode = false; + return cPlexBrowser::RecoverLastState(); + } + + if (cPlexMenu::eShow == menuShow::BROWSER) { + return new cPlexBrowser(tr("Browse Plex"), pPlexService); + } + return new cPlexMenu("Plex"); } @@ -216,33 +213,32 @@ cOsdMenu* cPlexMenu::ProcessMenu() ** ** @param key key event */ -eOSState cPlexMenu::ProcessKey(eKeys key) -{ - eOSState state; - - //if (key != kNone) { - // dsyslog("[plex]%s: key=%d\n", __FUNCTION__, key); - //} - // call standard function - state = cOsdMenu::ProcessKey(key); - - int current = Current(); // get current menu item index - cPlexOsdItem *item = static_cast<cPlexOsdItem*>(Get(current)); - - switch (state) { - case osUnknown: - switch (key) { - case kOk: - pPlexService = item->GetAttachedService(); - cPlexMenu::eShow = menuShow::BROWSER; - return osPlugin; // restart with OSD browser - default: - break; - } - default: - break; - } - return state; +eOSState cPlexMenu::ProcessKey(eKeys key) { + eOSState state; + + //if (key != kNone) { + // dsyslog("[plex]%s: key=%d\n", __FUNCTION__, key); + //} + // call standard function + state = cOsdMenu::ProcessKey(key); + + int current = Current(); // get current menu item index + cPlexOsdItem *item = static_cast<cPlexOsdItem *>(Get(current)); + + switch (state) { + case osUnknown: + switch (key) { + case kOk: + pPlexService = item->GetAttachedService(); + cPlexMenu::eShow = menuShow::BROWSER; + return osPlugin; // restart with OSD browser + default: + break; + } + default: + break; + } + return state; } @@ -26,31 +26,34 @@ enum menuShow { * Plex Browser */ -class cPlexBrowser :public cOsdMenu -{ +class cPlexBrowser : public cOsdMenu { private: - std::shared_ptr<plexclient::Plexservice> pService; - std::shared_ptr<plexclient::MediaContainer> pCont; - std::vector<plexclient::cVideo> *v_Vid; - std::vector<plexclient::Directory> *v_Dir; - std::vector<std::string> m_vStack; - std::string m_sSection; - std::string m_sActualPos; - /// Create a browser menu for current directory - void CreateMenu(); - /// Handle menu level up - eOSState LevelUp(void); - /// Handle menu item selection - eOSState ProcessSelected(); - - static std::shared_ptr<plexclient::Plexservice> pLastService; - static int lastCurrentItem; + std::shared_ptr<plexclient::Plexservice> pService; + std::shared_ptr<plexclient::MediaContainer> pCont; + std::vector<plexclient::cVideo> *v_Vid; + std::vector<plexclient::Directory> *v_Dir; + std::vector<std::string> m_vStack; + std::string m_sSection; + std::string m_sActualPos; + + /// Create a browser menu for current directory + void CreateMenu(); + + /// Handle menu level up + eOSState LevelUp(void); + + /// Handle menu item selection + eOSState ProcessSelected(); + + static std::shared_ptr<plexclient::Plexservice> pLastService; + static int lastCurrentItem; public: - cPlexBrowser(const char *title, std::shared_ptr<plexclient::Plexservice> Service); - virtual eOSState ProcessKey(eKeys); + cPlexBrowser(const char *title, std::shared_ptr<plexclient::Plexservice> Service); - static cPlexBrowser* RecoverLastState(); + virtual eOSState ProcessKey(eKeys); + + static cPlexBrowser *RecoverLastState(); }; @@ -58,14 +61,15 @@ public: /** ** Play plugin menu class. */ -class cPlexMenu:public cOsdMenu -{ +class cPlexMenu : public cOsdMenu { public: - cPlexMenu(const char *, int = 0, int = 0, int = 0, int = 0, int = 0); - virtual eOSState ProcessKey(eKeys); - - static cOsdMenu* ProcessMenu(); - static menuShow eShow; + cPlexMenu(const char *, int = 0, int = 0, int = 0, int = 0, int = 0); + + virtual eOSState ProcessKey(eKeys); + + static cOsdMenu *ProcessMenu(); + + static menuShow eShow; }; #endif // CPLEXOSD_H diff --git a/plexSdOsd.cpp b/plexSdOsd.cpp index ac699f2..f7f1228 100644 --- a/plexSdOsd.cpp +++ b/plexSdOsd.cpp @@ -7,413 +7,401 @@ cMutex cPlexSdOsd::RedrawMutex; -cPlexSdOsd::cPlexSdOsd(skindesignerapi::cPluginStructure *plugStruct) : cSkindesignerOsdObject(plugStruct) -{ - m_pRootView = NULL; +cPlexSdOsd::cPlexSdOsd(skindesignerapi::cPluginStructure *plugStruct) : cSkindesignerOsdObject(plugStruct) { + m_pRootView = NULL; } -cPlexSdOsd::~cPlexSdOsd() -{ - if(m_pRootView) - m_pRootView->Deactivate(true); - if(m_pBrowserGrid) - m_pBrowserGrid->Clear(); - if(m_pMessage) - m_pMessage->Clear(); +cPlexSdOsd::~cPlexSdOsd() { + if (m_pRootView) + m_pRootView->Deactivate(true); + if (m_pBrowserGrid) + m_pBrowserGrid->Clear(); + if (m_pMessage) + m_pMessage->Clear(); } -bool cPlexSdOsd::SdSupport() -{ - if (SkindesignerAvailable()) { - skindesignerapi::cOsdView *rootView = GetOsdView(); - if (!rootView) { - esyslog("[plex]: used skindesigner skin does not support plex"); - return false; - } - } - return true; +bool cPlexSdOsd::SdSupport() { + if (SkindesignerAvailable()) { + skindesignerapi::cOsdView *rootView = GetOsdView(); + if (!rootView) { + esyslog("[plex]: used skindesigner skin does not support plex"); + return false; + } + } + return true; } -void cPlexSdOsd::Show(void) -{ - if (!SkindesignerAvailable()) { - return; - } - - m_pRootView = std::shared_ptr<skindesignerapi::cOsdView>(GetOsdView((int)eViews::rootView)); - if (!m_pRootView) { - esyslog("[plex]: used skindesigner skin does not support plex"); - return; - } - - m_pBrowserGrid = std::shared_ptr<cBrowserGrid>(new cBrowserGrid(m_pRootView)); - m_pMessage = std::shared_ptr<skindesignerapi::cViewElement>(m_pRootView->GetViewElement((int)eViewElementsRoot::message)); - m_messageDisplayed = false; - m_detailsActive = false; - Flush(); +void cPlexSdOsd::Show(void) { + if (!SkindesignerAvailable()) { + return; + } + + m_pRootView = std::shared_ptr<skindesignerapi::cOsdView>(GetOsdView((int) eViews::rootView)); + if (!m_pRootView) { + esyslog("[plex]: used skindesigner skin does not support plex"); + return; + } + + m_pBrowserGrid = std::shared_ptr<cBrowserGrid>(new cBrowserGrid(m_pRootView)); + m_pMessage = std::shared_ptr<skindesignerapi::cViewElement>( + m_pRootView->GetViewElement((int) eViewElementsRoot::message)); + m_messageDisplayed = false; + m_detailsActive = false; + Flush(); } -void cPlexSdOsd::Flush() -{ - if(m_detailsActive) { - m_pDetailGrid->Draw(); - m_pDetailGrid->Flush(); - } - else { - m_pBrowserGrid->DrawGrid(); - m_pBrowserGrid->Flush(); - } +void cPlexSdOsd::Flush() { + if (m_detailsActive) { + m_pDetailGrid->Draw(); + m_pDetailGrid->Flush(); + } + else { + m_pBrowserGrid->DrawGrid(); + m_pBrowserGrid->Flush(); + } } -eOSState cPlexSdOsd::ProcessKey(eKeys Key) -{ - eOSState state = eOSState::osContinue; - - if(m_detailsActive) { - state = ProcessKeyDetailView(Key); - } else { - //check if some plexservers are online - if(plexclient::plexgdm::GetInstance().GetFirstServer() == NULL || - (plexclient::plexgdm::GetInstance().GetFirstServer() && plexclient::plexgdm::GetInstance().GetFirstServer()->Offline) - ) { - DrawMessage(std::string(tr("No Plex Media Server found."))); - switch (Key & ~k_Repeat) { - case kOk: - case kBack: - return eOSState::osEnd; - default: - return eOSState::osContinue; - } - } - state = ProcessKeyBrowserView(Key); - } - - return state; +eOSState cPlexSdOsd::ProcessKey(eKeys Key) { + eOSState state = eOSState::osContinue; + + if (m_detailsActive) { + state = ProcessKeyDetailView(Key); + } else { + //check if some plexservers are online + if (plexclient::plexgdm::GetInstance().GetFirstServer() == NULL || + (plexclient::plexgdm::GetInstance().GetFirstServer() && + plexclient::plexgdm::GetInstance().GetFirstServer()->Offline) + ) { + DrawMessage(std::string(tr("No Plex Media Server found."))); + switch (Key & ~k_Repeat) { + case kOk: + case kBack: + return eOSState::osEnd; + default: + return eOSState::osContinue; + } + } + state = ProcessKeyBrowserView(Key); + } + + return state; } -eOSState cPlexSdOsd::ProcessKeyDetailView(eKeys Key) -{ - eOSState state = eOSState::osContinue; - plexclient::cVideo* vid = NULL; - - switch (Key & ~k_Repeat) { - case kUp: - if(m_pDetailGrid->NavigateUp()) Flush(); - break; - case kDown: - if(m_pDetailGrid->NavigateDown()) Flush(); - break; - case kLeft: - if(m_pDetailGrid->NavigateLeft()) Flush(); - break; - case kRight: - if(m_pDetailGrid->NavigateRight()) Flush(); - break; - case kOk: - state = m_pDetailGrid->NavigateSelect(); - vid = dynamic_cast<plexclient::cVideo*>(m_pDetailGrid->SelectedObject()); - Flush(); - break; - case kBack: - state = eOSState::osContinue; - m_pDetailGrid->Clear(); - m_pDetailGrid->Deactivate(true); - m_pDetailGrid = nullptr; - m_pDetailsView = nullptr; - m_detailsActive = false; - m_pBrowserGrid->Activate(); - Flush(); - break; - case kYellow: - if(m_pDetailGrid->GetVideo()) { - if(m_pDetailGrid->GetVideo()->m_iViewCount > 0) m_pDetailGrid->GetVideo()->SetUnwatched(); - else m_pDetailGrid->GetVideo()->SetWatched(); - m_pDetailGrid->GetVideo()->UpdateFromServer(); - Flush(); - } - break; - case kGreen: - vid = m_pDetailGrid->GetVideo(); - state = eOSState::osUser1; - break; - case kRed: - vid = m_pDetailGrid->GetVideo(); - vid->m_iMyPlayOffset = vid->m_lViewoffset/1000; - state = eOSState::osUser1; - break; - case kBlue: - default: - break; - } - - if(state == eOSState::osUser1 && vid) { - cMyPlugin::PlayFile(*vid); - state = eOSState::osEnd; - } - - if (state != osEnd && m_pDetailGrid && m_pDetailGrid->DrawTime()) m_pDetailGrid->Flush(); - - return state; +eOSState cPlexSdOsd::ProcessKeyDetailView(eKeys Key) { + eOSState state = eOSState::osContinue; + plexclient::cVideo *vid = NULL; + + switch (Key & ~k_Repeat) { + case kUp: + if (m_pDetailGrid->NavigateUp()) Flush(); + break; + case kDown: + if (m_pDetailGrid->NavigateDown()) Flush(); + break; + case kLeft: + if (m_pDetailGrid->NavigateLeft()) Flush(); + break; + case kRight: + if (m_pDetailGrid->NavigateRight()) Flush(); + break; + case kOk: + state = m_pDetailGrid->NavigateSelect(); + vid = dynamic_cast<plexclient::cVideo *>(m_pDetailGrid->SelectedObject()); + Flush(); + break; + case kBack: + state = eOSState::osContinue; + m_pDetailGrid->Clear(); + m_pDetailGrid->Deactivate(true); + m_pDetailGrid = nullptr; + m_pDetailsView = nullptr; + m_detailsActive = false; + m_pBrowserGrid->Activate(); + Flush(); + break; + case kYellow: + if (m_pDetailGrid->GetVideo()) { + if (m_pDetailGrid->GetVideo()->m_iViewCount > 0) m_pDetailGrid->GetVideo()->SetUnwatched(); + else m_pDetailGrid->GetVideo()->SetWatched(); + m_pDetailGrid->GetVideo()->UpdateFromServer(); + Flush(); + } + break; + case kGreen: + vid = m_pDetailGrid->GetVideo(); + state = eOSState::osUser1; + break; + case kRed: + vid = m_pDetailGrid->GetVideo(); + vid->m_iMyPlayOffset = vid->m_lViewoffset / 1000; + state = eOSState::osUser1; + break; + case kBlue: + default: + break; + } + + if (state == eOSState::osUser1 && vid) { + cMyPlugin::PlayFile(*vid); + state = eOSState::osEnd; + } + + if (state != osEnd && m_pDetailGrid && m_pDetailGrid->DrawTime()) m_pDetailGrid->Flush(); + + return state; } -eOSState cPlexSdOsd::ProcessKeyBrowserView(eKeys Key) -{ - eOSState state = eOSState::osContinue; - plexclient::cVideo* vid = NULL; - - switch (Key & ~k_Repeat) { - case kUp: - if(m_pBrowserGrid->NavigateUp()) Flush(); - break; - case kDown: - if(m_pBrowserGrid->NavigateDown()) Flush(); - break; - case kLeft: - if(m_pBrowserGrid->NavigateLeft()) Flush(); - break; - case kRight: - if(m_pBrowserGrid->NavigateRight()) Flush(); - break; - case kOk: - // Play movie or change dir - state = m_pBrowserGrid->NavigateSelect(); - if(state == eOSState::osUser1) { - vid = dynamic_cast<plexclient::cVideo*>(m_pBrowserGrid->SelectedObject()); - vid->m_iMyPlayOffset = vid->m_lViewoffset/1000; - } - Flush(); - break; - case kBack: - state = m_pBrowserGrid->NavigateBack(); - Flush(); - break; - case kBlue: - m_pBrowserGrid->NextViewMode(); - Flush(); - break; - case kRed: - vid = dynamic_cast<plexclient::cVideo*>(m_pBrowserGrid->SelectedObject()); - if(vid) { - if(vid->m_iViewCount > 0) vid->SetUnwatched(); - else vid->SetWatched(); - vid->UpdateFromServer(); - Flush(); - } - break; - case kGreen: // Show Details OSD - vid = dynamic_cast<plexclient::cVideo*>(m_pBrowserGrid->SelectedObject()); - if(vid) { - vid->UpdateFromServer(); - ShowDetails(vid); - } - break; - case kYellow: - m_pBrowserGrid->NextTab(); - Flush(); - break; - default: - break; - } - - if(state == eOSState::osUser1 && vid) { - cMyPlugin::PlayFile(*vid); - state = eOSState::osEnd; - } - - if (state != osEnd && m_pBrowserGrid->DrawTime()) m_pBrowserGrid->Flush(); - - return state; +eOSState cPlexSdOsd::ProcessKeyBrowserView(eKeys Key) { + eOSState state = eOSState::osContinue; + plexclient::cVideo *vid = NULL; + + switch (Key & ~k_Repeat) { + case kUp: + if (m_pBrowserGrid->NavigateUp()) Flush(); + break; + case kDown: + if (m_pBrowserGrid->NavigateDown()) Flush(); + break; + case kLeft: + if (m_pBrowserGrid->NavigateLeft()) Flush(); + break; + case kRight: + if (m_pBrowserGrid->NavigateRight()) Flush(); + break; + case kOk: + // Play movie or change dir + state = m_pBrowserGrid->NavigateSelect(); + if (state == eOSState::osUser1) { + vid = dynamic_cast<plexclient::cVideo *>(m_pBrowserGrid->SelectedObject()); + vid->m_iMyPlayOffset = vid->m_lViewoffset / 1000; + } + Flush(); + break; + case kBack: + state = m_pBrowserGrid->NavigateBack(); + Flush(); + break; + case kBlue: + m_pBrowserGrid->NextViewMode(); + Flush(); + break; + case kRed: + vid = dynamic_cast<plexclient::cVideo *>(m_pBrowserGrid->SelectedObject()); + if (vid) { + if (vid->m_iViewCount > 0) vid->SetUnwatched(); + else vid->SetWatched(); + vid->UpdateFromServer(); + Flush(); + } + break; + case kGreen: // Show Details OSD + vid = dynamic_cast<plexclient::cVideo *>(m_pBrowserGrid->SelectedObject()); + if (vid) { + vid->UpdateFromServer(); + ShowDetails(vid); + } + break; + case kYellow: + m_pBrowserGrid->NextTab(); + Flush(); + break; + default: + break; + } + + if (state == eOSState::osUser1 && vid) { + cMyPlugin::PlayFile(*vid); + state = eOSState::osEnd; + } + + if (state != osEnd && m_pBrowserGrid->DrawTime()) m_pBrowserGrid->Flush(); + + return state; } -void cPlexSdOsd::ShowDetails(plexclient::cVideo *vid) -{ - if(m_detailsActive) return; - - m_pBrowserGrid->Deactivate(true); - m_pDetailsView = std::shared_ptr<skindesignerapi::cOsdView>(GetOsdView((int)eViews::detailView)); - m_pDetailGrid = std::shared_ptr<cDetailView>(new cDetailView(m_pDetailsView, vid)); - - m_pDetailGrid->Activate(); - m_pDetailGrid->Draw(); - m_pDetailGrid->Flush(); - m_detailsActive = true; +void cPlexSdOsd::ShowDetails(plexclient::cVideo *vid) { + if (m_detailsActive) return; + + m_pBrowserGrid->Deactivate(true); + m_pDetailsView = std::shared_ptr<skindesignerapi::cOsdView>(GetOsdView((int) eViews::detailView)); + m_pDetailGrid = std::shared_ptr<cDetailView>(new cDetailView(m_pDetailsView, vid)); + + m_pDetailGrid->Activate(); + m_pDetailGrid->Draw(); + m_pDetailGrid->Flush(); + m_detailsActive = true; } -void cPlexSdOsd::DrawMessage(std::string message) -{ - m_pMessage->ClearTokens(); - m_pMessage->AddStringToken((int)eTokenMessageStr::message, message.c_str()); - m_pMessage->AddIntToken((int)eTokenMessageInt::displaymessage, true); - m_pMessage->Display(); - m_pRootView->Display(); +void cPlexSdOsd::DrawMessage(std::string message) { + m_pMessage->ClearTokens(); + m_pMessage->AddStringToken((int) eTokenMessageStr::message, message.c_str()); + m_pMessage->AddIntToken((int) eTokenMessageInt::displaymessage, true); + m_pMessage->Display(); + m_pRootView->Display(); } -void cPlexSdOsd::DefineTokens(eViewElementsRoot ve, skindesignerapi::cTokenContainer* tk) -{ - switch(ve) { - case eViewElementsRoot::background: - tk->DefineIntToken("{viewmode}", (int)eTokenBackgroundInt::viewmode); - tk->DefineIntToken("{isdirectory}", (int)eTokenBackgroundInt::isdirectory); - tk->DefineStringToken("{selecteditembackground}", (int)eTokenBackgroundStr::selecteditembackground); - tk->DefineStringToken("{currentdirectorybackground}", (int)eTokenBackgroundStr::currentdirectorybackground); - break; - case eViewElementsRoot::infopane: - case eViewElementsRoot::header: - DefineGridTokens(tk); - tk->DefineStringToken("{tabname}", (int)eTokenGridStr::tabname); - break; - case eViewElementsRoot::footer: - DefineFooterTokens(tk); - break; - case eViewElementsRoot::watch: - DefineWatchTokens(tk); - break; - case eViewElementsRoot::message: - tk->DefineIntToken("{displaymessage}", (int)eTokenMessageInt::displaymessage); - tk->DefineStringToken("{message}", (int)eTokenMessageStr::message); - break; - case eViewElementsRoot::scrollbar: - tk->DefineIntToken("{height}", (int)eTokenScrollbarInt::height); - tk->DefineIntToken("{offset}", (int)eTokenScrollbarInt::offset); - tk->DefineIntToken("{hasscrollbar}", (int)eTokenScrollbarInt::hasscrollbar); - break; - } +void cPlexSdOsd::DefineTokens(eViewElementsRoot ve, skindesignerapi::cTokenContainer *tk) { + switch (ve) { + case eViewElementsRoot::background: + tk->DefineIntToken("{viewmode}", (int) eTokenBackgroundInt::viewmode); + tk->DefineIntToken("{isdirectory}", (int) eTokenBackgroundInt::isdirectory); + tk->DefineStringToken("{selecteditembackground}", (int) eTokenBackgroundStr::selecteditembackground); + tk->DefineStringToken("{currentdirectorybackground}", + (int) eTokenBackgroundStr::currentdirectorybackground); + break; + case eViewElementsRoot::infopane: + case eViewElementsRoot::header: + DefineGridTokens(tk); + tk->DefineStringToken("{tabname}", (int) eTokenGridStr::tabname); + break; + case eViewElementsRoot::footer: + DefineFooterTokens(tk); + break; + case eViewElementsRoot::watch: + DefineWatchTokens(tk); + break; + case eViewElementsRoot::message: + tk->DefineIntToken("{displaymessage}", (int) eTokenMessageInt::displaymessage); + tk->DefineStringToken("{message}", (int) eTokenMessageStr::message); + break; + case eViewElementsRoot::scrollbar: + tk->DefineIntToken("{height}", (int) eTokenScrollbarInt::height); + tk->DefineIntToken("{offset}", (int) eTokenScrollbarInt::offset); + tk->DefineIntToken("{hasscrollbar}", (int) eTokenScrollbarInt::hasscrollbar); + break; + } } -void cPlexSdOsd::DefineGridTokens(skindesignerapi::cTokenContainer* tk) -{ - tk->DefineIntToken("{viewmode}", (int)eTokenGridInt::viewmode); - tk->DefineIntToken("{viewgroup}", (int)eTokenGridInt::viewgroup); - tk->DefineIntToken("{viewCount}", (int)eTokenGridInt::viewCount); - tk->DefineIntToken("{viewoffset}", (int)eTokenGridInt::viewoffset); - tk->DefineIntToken("{viewoffsetpercent}", (int)eTokenGridInt::viewoffsetpercent); - tk->DefineIntToken("{duration}", (int)eTokenGridInt::duration); - tk->DefineIntToken("{year}", (int)eTokenGridInt::year); - tk->DefineIntToken("{hasthumb}", (int)eTokenGridInt::hasthumb); - tk->DefineIntToken("{hasart}", (int)eTokenGridInt::hasart); - tk->DefineIntToken("{ismovie}", (int)eTokenGridInt::ismovie); - tk->DefineIntToken("{isepisode}", (int)eTokenGridInt::isepisode); - tk->DefineIntToken("{isdirectory}", (int)eTokenGridInt::isdirectory); - tk->DefineIntToken("{isshow}", (int)eTokenGridInt::isshow); - tk->DefineIntToken("{isseason}", (int)eTokenGridInt::isseason); - tk->DefineIntToken("{isclip}", (int)eTokenGridInt::isclip); - tk->DefineIntToken("{originallyAvailableYear}", (int)eTokenGridInt::originallyAvailableYear); - tk->DefineIntToken("{originallyAvailableMonth}", (int)eTokenGridInt::originallyAvailableMonth); - tk->DefineIntToken("{originallyAvailableDay}", (int)eTokenGridInt::originallyAvailableDay); - tk->DefineIntToken("{season}", (int)eTokenGridInt::season); - tk->DefineIntToken("{episode}", (int)eTokenGridInt::episode); - tk->DefineIntToken("{leafCount}", (int)eTokenGridInt::leafCount); - tk->DefineIntToken("{viewedLeafCount}", (int)eTokenGridInt::viewedLeafCount); - tk->DefineIntToken("{childCount}", (int)eTokenGridInt::childCount); - tk->DefineIntToken("{rating}", (int)eTokenGridInt::rating); - tk->DefineIntToken("{hasseriesthumb}", (int)eTokenGridInt::hasseriesthumb); - tk->DefineIntToken("{hasbanner}", (int)eTokenGridInt::hasbanner); - tk->DefineIntToken("{columns}", (int)eTokenGridInt::columns); - tk->DefineIntToken("{rows}", (int)eTokenGridInt::rows); - tk->DefineIntToken("{position}", (int)eTokenGridInt::position); - tk->DefineIntToken("{totalcount}", (int)eTokenGridInt::totalcount); - tk->DefineIntToken("{bitrate}", (int)eTokenGridInt::bitrate); - tk->DefineIntToken("{width}", (int)eTokenGridInt::width); - tk->DefineIntToken("{height}", (int)eTokenGridInt::height); - tk->DefineIntToken("{audioChannels}", (int)eTokenGridInt::audioChannels); - tk->DefineIntToken("{isdummy}", (int)eTokenGridInt::isdummy); - tk->DefineIntToken("{isserver}", (int)eTokenGridInt::isserver); - tk->DefineIntToken("{serverport}", (int)eTokenGridInt::serverport); - tk->DefineIntToken("{extratype}", (int)eTokenGridInt::extratype); - - tk->DefineStringToken("{title}", (int)eTokenGridStr::title); - tk->DefineStringToken("{orginaltitle}", (int)eTokenGridStr::orginaltitle); - tk->DefineStringToken("{summary}", (int)eTokenGridStr::summary); - tk->DefineStringToken("{tagline}", (int)eTokenGridStr::tagline); - tk->DefineStringToken("{contentrating}", (int)eTokenGridStr::contentrating); - tk->DefineStringToken("{ratingstring}", (int)eTokenGridStr::ratingstring); - tk->DefineStringToken("{studio}", (int)eTokenGridStr::studio); - tk->DefineStringToken("{thumb}", (int)eTokenGridStr::thumb); - tk->DefineStringToken("{art}", (int)eTokenGridStr::art); - tk->DefineStringToken("{seriestitle}", (int)eTokenGridStr::seriestitle); - tk->DefineStringToken("{seriesthumb}", (int)eTokenGridStr::seriesthumb); - tk->DefineStringToken("{banner}", (int)eTokenGridStr::banner); - tk->DefineStringToken("{videoResolution}", (int)eTokenGridStr::videoResolution); - tk->DefineStringToken("{aspectRatio}", (int)eTokenGridStr::aspectRatio); - tk->DefineStringToken("{audioCodec}", (int)eTokenGridStr::audioCodec); - tk->DefineStringToken("{videoCodec}", (int)eTokenGridStr::videoCodec); - tk->DefineStringToken("{container}", (int)eTokenGridStr::container); - tk->DefineStringToken("{videoFrameRate}", (int)eTokenGridStr::videoFrameRate); - tk->DefineStringToken("{serverstartpointname}", (int)eTokenGridStr::serverstartpointname); - tk->DefineStringToken("{serverip}", (int)eTokenGridStr::serverip); - tk->DefineStringToken("{serverversion}", (int)eTokenGridStr::serverversion); - - tk->DefineLoopToken("{roles[actor]}", (int)eTokenGridActorLst::roles); - tk->DefineLoopToken("{genres[genre]}", (int)eTokenGridGenresLst::genres); +void cPlexSdOsd::DefineGridTokens(skindesignerapi::cTokenContainer *tk) { + tk->DefineIntToken("{viewmode}", (int) eTokenGridInt::viewmode); + tk->DefineIntToken("{viewgroup}", (int) eTokenGridInt::viewgroup); + tk->DefineIntToken("{viewCount}", (int) eTokenGridInt::viewCount); + tk->DefineIntToken("{viewoffset}", (int) eTokenGridInt::viewoffset); + tk->DefineIntToken("{viewoffsetpercent}", (int) eTokenGridInt::viewoffsetpercent); + tk->DefineIntToken("{duration}", (int) eTokenGridInt::duration); + tk->DefineIntToken("{year}", (int) eTokenGridInt::year); + tk->DefineIntToken("{hasthumb}", (int) eTokenGridInt::hasthumb); + tk->DefineIntToken("{hasart}", (int) eTokenGridInt::hasart); + tk->DefineIntToken("{ismovie}", (int) eTokenGridInt::ismovie); + tk->DefineIntToken("{isepisode}", (int) eTokenGridInt::isepisode); + tk->DefineIntToken("{isdirectory}", (int) eTokenGridInt::isdirectory); + tk->DefineIntToken("{isshow}", (int) eTokenGridInt::isshow); + tk->DefineIntToken("{isseason}", (int) eTokenGridInt::isseason); + tk->DefineIntToken("{isclip}", (int) eTokenGridInt::isclip); + tk->DefineIntToken("{originallyAvailableYear}", (int) eTokenGridInt::originallyAvailableYear); + tk->DefineIntToken("{originallyAvailableMonth}", (int) eTokenGridInt::originallyAvailableMonth); + tk->DefineIntToken("{originallyAvailableDay}", (int) eTokenGridInt::originallyAvailableDay); + tk->DefineIntToken("{season}", (int) eTokenGridInt::season); + tk->DefineIntToken("{episode}", (int) eTokenGridInt::episode); + tk->DefineIntToken("{leafCount}", (int) eTokenGridInt::leafCount); + tk->DefineIntToken("{viewedLeafCount}", (int) eTokenGridInt::viewedLeafCount); + tk->DefineIntToken("{childCount}", (int) eTokenGridInt::childCount); + tk->DefineIntToken("{rating}", (int) eTokenGridInt::rating); + tk->DefineIntToken("{hasseriesthumb}", (int) eTokenGridInt::hasseriesthumb); + tk->DefineIntToken("{hasbanner}", (int) eTokenGridInt::hasbanner); + tk->DefineIntToken("{columns}", (int) eTokenGridInt::columns); + tk->DefineIntToken("{rows}", (int) eTokenGridInt::rows); + tk->DefineIntToken("{position}", (int) eTokenGridInt::position); + tk->DefineIntToken("{totalcount}", (int) eTokenGridInt::totalcount); + tk->DefineIntToken("{bitrate}", (int) eTokenGridInt::bitrate); + tk->DefineIntToken("{width}", (int) eTokenGridInt::width); + tk->DefineIntToken("{height}", (int) eTokenGridInt::height); + tk->DefineIntToken("{audioChannels}", (int) eTokenGridInt::audioChannels); + tk->DefineIntToken("{isdummy}", (int) eTokenGridInt::isdummy); + tk->DefineIntToken("{isserver}", (int) eTokenGridInt::isserver); + tk->DefineIntToken("{serverport}", (int) eTokenGridInt::serverport); + tk->DefineIntToken("{extratype}", (int) eTokenGridInt::extratype); + + tk->DefineStringToken("{title}", (int) eTokenGridStr::title); + tk->DefineStringToken("{orginaltitle}", (int) eTokenGridStr::orginaltitle); + tk->DefineStringToken("{summary}", (int) eTokenGridStr::summary); + tk->DefineStringToken("{tagline}", (int) eTokenGridStr::tagline); + tk->DefineStringToken("{contentrating}", (int) eTokenGridStr::contentrating); + tk->DefineStringToken("{ratingstring}", (int) eTokenGridStr::ratingstring); + tk->DefineStringToken("{studio}", (int) eTokenGridStr::studio); + tk->DefineStringToken("{thumb}", (int) eTokenGridStr::thumb); + tk->DefineStringToken("{art}", (int) eTokenGridStr::art); + tk->DefineStringToken("{seriestitle}", (int) eTokenGridStr::seriestitle); + tk->DefineStringToken("{seriesthumb}", (int) eTokenGridStr::seriesthumb); + tk->DefineStringToken("{banner}", (int) eTokenGridStr::banner); + tk->DefineStringToken("{videoResolution}", (int) eTokenGridStr::videoResolution); + tk->DefineStringToken("{aspectRatio}", (int) eTokenGridStr::aspectRatio); + tk->DefineStringToken("{audioCodec}", (int) eTokenGridStr::audioCodec); + tk->DefineStringToken("{videoCodec}", (int) eTokenGridStr::videoCodec); + tk->DefineStringToken("{container}", (int) eTokenGridStr::container); + tk->DefineStringToken("{videoFrameRate}", (int) eTokenGridStr::videoFrameRate); + tk->DefineStringToken("{serverstartpointname}", (int) eTokenGridStr::serverstartpointname); + tk->DefineStringToken("{serverip}", (int) eTokenGridStr::serverip); + tk->DefineStringToken("{serverversion}", (int) eTokenGridStr::serverversion); + + tk->DefineLoopToken("{roles[actor]}", (int) eTokenGridActorLst::roles); + tk->DefineLoopToken("{genres[genre]}", (int) eTokenGridGenresLst::genres); } -void cPlexSdOsd::DefineFooterTokens(skindesignerapi::cTokenContainer *tk) -{ - tk->DefineIntToken("{red1}", (int)eTokenFooterInt::red1); - tk->DefineIntToken("{red2}", (int)eTokenFooterInt::red2); - tk->DefineIntToken("{red3}", (int)eTokenFooterInt::red3); - tk->DefineIntToken("{red4}", (int)eTokenFooterInt::red4); - tk->DefineIntToken("{green1}", (int)eTokenFooterInt::green1); - tk->DefineIntToken("{green2}", (int)eTokenFooterInt::green2); - tk->DefineIntToken("{green3}", (int)eTokenFooterInt::green3); - tk->DefineIntToken("{green4}", (int)eTokenFooterInt::green4); - tk->DefineIntToken("{yellow1}", (int)eTokenFooterInt::yellow1); - tk->DefineIntToken("{yellow2}", (int)eTokenFooterInt::yellow2); - tk->DefineIntToken("{yellow3}", (int)eTokenFooterInt::yellow3); - tk->DefineIntToken("{yellow4}", (int)eTokenFooterInt::yellow4); - tk->DefineIntToken("{blue1}", (int)eTokenFooterInt::blue1); - tk->DefineIntToken("{blue2}", (int)eTokenFooterInt::blue2); - tk->DefineIntToken("{blue3}", (int)eTokenFooterInt::blue3); - tk->DefineIntToken("{blue4}", (int)eTokenFooterInt::blue4); - tk->DefineStringToken("{red}", (int)eTokenFooterStr::red); - tk->DefineStringToken("{green}", (int)eTokenFooterStr::green); - tk->DefineStringToken("{yellow}", (int)eTokenFooterStr::yellow); - tk->DefineStringToken("{blue}", (int)eTokenFooterStr::blue); +void cPlexSdOsd::DefineFooterTokens(skindesignerapi::cTokenContainer *tk) { + tk->DefineIntToken("{red1}", (int) eTokenFooterInt::red1); + tk->DefineIntToken("{red2}", (int) eTokenFooterInt::red2); + tk->DefineIntToken("{red3}", (int) eTokenFooterInt::red3); + tk->DefineIntToken("{red4}", (int) eTokenFooterInt::red4); + tk->DefineIntToken("{green1}", (int) eTokenFooterInt::green1); + tk->DefineIntToken("{green2}", (int) eTokenFooterInt::green2); + tk->DefineIntToken("{green3}", (int) eTokenFooterInt::green3); + tk->DefineIntToken("{green4}", (int) eTokenFooterInt::green4); + tk->DefineIntToken("{yellow1}", (int) eTokenFooterInt::yellow1); + tk->DefineIntToken("{yellow2}", (int) eTokenFooterInt::yellow2); + tk->DefineIntToken("{yellow3}", (int) eTokenFooterInt::yellow3); + tk->DefineIntToken("{yellow4}", (int) eTokenFooterInt::yellow4); + tk->DefineIntToken("{blue1}", (int) eTokenFooterInt::blue1); + tk->DefineIntToken("{blue2}", (int) eTokenFooterInt::blue2); + tk->DefineIntToken("{blue3}", (int) eTokenFooterInt::blue3); + tk->DefineIntToken("{blue4}", (int) eTokenFooterInt::blue4); + tk->DefineStringToken("{red}", (int) eTokenFooterStr::red); + tk->DefineStringToken("{green}", (int) eTokenFooterStr::green); + tk->DefineStringToken("{yellow}", (int) eTokenFooterStr::yellow); + tk->DefineStringToken("{blue}", (int) eTokenFooterStr::blue); } -void cPlexSdOsd::DefineWatchTokens(skindesignerapi::cTokenContainer *tk) -{ - tk->DefineIntToken("{sec}", (int)eTokenTimeInt::sec); - tk->DefineIntToken("{min}", (int)eTokenTimeInt::min); - tk->DefineIntToken("{hour}", (int)eTokenTimeInt::hour); - tk->DefineIntToken("{hmins}", (int)eTokenTimeInt::hmins); - tk->DefineIntToken("{day}", (int)eTokenTimeInt::day); - tk->DefineIntToken("{year}", (int)eTokenTimeInt::year); - tk->DefineStringToken("{time}", (int)eTokenTimeStr::time); - tk->DefineStringToken("{dayname}", (int)eTokenTimeStr::dayname); - tk->DefineStringToken("{daynameshort}", (int)eTokenTimeStr::daynameshort); - tk->DefineStringToken("{dayleadingzero}", (int)eTokenTimeStr::dayleadingzero); - tk->DefineStringToken("{month}", (int)eTokenTimeStr::month); - tk->DefineStringToken("{monthname}", (int)eTokenTimeStr::monthname); - tk->DefineStringToken("{monthnameshort}", (int)eTokenTimeStr::monthnameshort); +void cPlexSdOsd::DefineWatchTokens(skindesignerapi::cTokenContainer *tk) { + tk->DefineIntToken("{sec}", (int) eTokenTimeInt::sec); + tk->DefineIntToken("{min}", (int) eTokenTimeInt::min); + tk->DefineIntToken("{hour}", (int) eTokenTimeInt::hour); + tk->DefineIntToken("{hmins}", (int) eTokenTimeInt::hmins); + tk->DefineIntToken("{day}", (int) eTokenTimeInt::day); + tk->DefineIntToken("{year}", (int) eTokenTimeInt::year); + tk->DefineStringToken("{time}", (int) eTokenTimeStr::time); + tk->DefineStringToken("{dayname}", (int) eTokenTimeStr::dayname); + tk->DefineStringToken("{daynameshort}", (int) eTokenTimeStr::daynameshort); + tk->DefineStringToken("{dayleadingzero}", (int) eTokenTimeStr::dayleadingzero); + tk->DefineStringToken("{month}", (int) eTokenTimeStr::month); + tk->DefineStringToken("{monthname}", (int) eTokenTimeStr::monthname); + tk->DefineStringToken("{monthnameshort}", (int) eTokenTimeStr::monthnameshort); } -void cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail ve, skindesignerapi::cTokenContainer *tk) -{ - switch(ve) { - case eViewElementsDetail::background: - tk->DefineIntToken("{hasfanart}", (int)eTokenDetailBackgroundInt::hasfanart); - tk->DefineIntToken("{hascover}", (int)eTokenDetailBackgroundInt::hascover); - tk->DefineStringToken("{fanartpath}", (int)eTokenDetailBackgroundStr::fanartpath); - tk->DefineStringToken("{coverpath}", (int)eTokenDetailBackgroundStr::coverpath); - break; - case eViewElementsDetail::footer: - DefineFooterTokens(tk); - break; - case eViewElementsDetail::info: - DefineGridTokens(tk); - break; - case eViewElementsDetail::message: - tk->DefineIntToken("{displaymessage}", (int)eTokenMessageInt::displaymessage); - tk->DefineStringToken("{message}", (int)eTokenMessageStr::message); - break; - case eViewElementsDetail::scrollbar: - tk->DefineIntToken("{height}", (int)eTokenScrollbarInt::height); - tk->DefineIntToken("{offset}", (int)eTokenScrollbarInt::offset); - tk->DefineIntToken("{hasscrollbar}", (int)eTokenScrollbarInt::hasscrollbar); - break; - default: - break; - } +void cPlexSdOsd::DefineDetailsTokens(eViewElementsDetail ve, skindesignerapi::cTokenContainer *tk) { + switch (ve) { + case eViewElementsDetail::background: + tk->DefineIntToken("{hasfanart}", (int) eTokenDetailBackgroundInt::hasfanart); + tk->DefineIntToken("{hascover}", (int) eTokenDetailBackgroundInt::hascover); + tk->DefineStringToken("{fanartpath}", (int) eTokenDetailBackgroundStr::fanartpath); + tk->DefineStringToken("{coverpath}", (int) eTokenDetailBackgroundStr::coverpath); + break; + case eViewElementsDetail::footer: + DefineFooterTokens(tk); + break; + case eViewElementsDetail::info: + DefineGridTokens(tk); + break; + case eViewElementsDetail::message: + tk->DefineIntToken("{displaymessage}", (int) eTokenMessageInt::displaymessage); + tk->DefineStringToken("{message}", (int) eTokenMessageStr::message); + break; + case eViewElementsDetail::scrollbar: + tk->DefineIntToken("{height}", (int) eTokenScrollbarInt::height); + tk->DefineIntToken("{offset}", (int) eTokenScrollbarInt::offset); + tk->DefineIntToken("{hasscrollbar}", (int) eTokenScrollbarInt::hasscrollbar); + break; + default: + break; + } } diff --git a/plexSdOsd.h b/plexSdOsd.h index 4549400..5e299cd 100644 --- a/plexSdOsd.h +++ b/plexSdOsd.h @@ -22,38 +22,49 @@ #include <libskindesignerapi/osdelements.h> #include <libskindesignerapi/skindesignerosdbase.h> -class cPlexSdOsd : public skindesignerapi::cSkindesignerOsdObject -{ -private: - std::shared_ptr<cBrowserGrid> m_pBrowserGrid; - std::shared_ptr<cDetailView> m_pDetailGrid; - std::shared_ptr<skindesignerapi::cViewElement> m_pMessage; - bool m_messageDisplayed; - bool m_detailsActive; - - std::shared_ptr<skindesignerapi::cOsdView> m_pRootView; - std::shared_ptr<skindesignerapi::cOsdView> m_pDetailsView; - - void Flush(); - void DrawMessage(std::string message); - - void ShowDetails(plexclient::cVideo *vid); - +class cPlexSdOsd : public skindesignerapi::cSkindesignerOsdObject { +private: + std::shared_ptr<cBrowserGrid> m_pBrowserGrid; + std::shared_ptr<cDetailView> m_pDetailGrid; + std::shared_ptr<skindesignerapi::cViewElement> m_pMessage; + bool m_messageDisplayed; + bool m_detailsActive; + + std::shared_ptr<skindesignerapi::cOsdView> m_pRootView; + std::shared_ptr<skindesignerapi::cOsdView> m_pDetailsView; + + void Flush(); + + void DrawMessage(std::string message); + + void ShowDetails(plexclient::cVideo *vid); + public: - cPlexSdOsd(skindesignerapi::cPluginStructure *plugStruct); - ~cPlexSdOsd(); - virtual void Show(void); - virtual eOSState ProcessKey(eKeys Key); - eOSState ProcessKeyDetailView(eKeys Key); - eOSState ProcessKeyBrowserView(eKeys Key); - - bool SdSupport(); - static cMutex RedrawMutex; - static void DefineTokens(eViewElementsRoot ve, skindesignerapi::cTokenContainer *tk); - static void DefineGridTokens(skindesignerapi::cTokenContainer *tk); - static void DefineFooterTokens(skindesignerapi::cTokenContainer *tk); - static void DefineWatchTokens(skindesignerapi::cTokenContainer *tk); - static void DefineDetailsTokens(eViewElementsDetail ve, skindesignerapi::cTokenContainer *tk); + cPlexSdOsd(skindesignerapi::cPluginStructure *plugStruct); + + ~cPlexSdOsd(); + + virtual void Show(void); + + virtual eOSState ProcessKey(eKeys Key); + + eOSState ProcessKeyDetailView(eKeys Key); + + eOSState ProcessKeyBrowserView(eKeys Key); + + bool SdSupport(); + + static cMutex RedrawMutex; + + static void DefineTokens(eViewElementsRoot ve, skindesignerapi::cTokenContainer *tk); + + static void DefineGridTokens(skindesignerapi::cTokenContainer *tk); + + static void DefineFooterTokens(skindesignerapi::cTokenContainer *tk); + + static void DefineWatchTokens(skindesignerapi::cTokenContainer *tk); + + static void DefineDetailsTokens(eViewElementsDetail ve, skindesignerapi::cTokenContainer *tk); }; #endif // CPLEXSDOSD_H diff --git a/plexgdm.cpp b/plexgdm.cpp index e274689..c0d2cb0 100644 --- a/plexgdm.cpp +++ b/plexgdm.cpp @@ -4,247 +4,239 @@ #include <ctime> #include "Plexservice.h" -namespace plexclient -{ - -plexgdm::plexgdm() -{ - _discoverMessage = "M-SEARCH * HTTP/1.0"; - _clientHeader = "* HTTP/1.0"; - _multicastAddress = "239.0.0.250"; - _clientUpdatePort = 32412; - _helloSent = false; - _discoverInterval = 30 * 1000; - _discoverTimer.Set(1); - - m_discoverAdress = Poco::Net::SocketAddress(_multicastAddress, 32414); - m_clientRegisterGroup = Poco::Net::SocketAddress(_multicastAddress, 32413); - - m_discoveryComplete = false; - m_registrationIsRunning = false; - m_clientRegistered = false; - m_discoveryInterval = 120; - m_discoveryIsRunning = false; -} - -plexgdm::~plexgdm() -{ -} - -void plexgdm::clientDetails(std::string c_id, - std::string c_name, - std::string c_port, - std::string c_product, - std::string c_version) -{ - _clientData = "Content-Type: plex/media-player\r\n" - "Resource-Identifier: " + c_id + "\r\n" - "Device-Class: PC\r\n" - "Name: " + c_name + "\r\n" - "Port: " + c_port + "\r\n" - "Product: " + c_product + "\r\n" - "Protocol: plex\r\n" - "Protocol-Capabilities: navigation,playback,timeline\r\n" - "Protocol-Version: 1\r\n" - "Version: " + c_version + "\r\n"; - _clientId = c_id; -} - -std::string plexgdm::getClientDetails() -{ - if(_clientData.empty()) - throw "client_Data not initialized"; - return _clientData; -} - -void plexgdm::Action() -{ - if(Config::GetInstance().UseConfiguredServer) { - // Adds a Server to vector - GetServer(Config::GetInstance().s_serverHost, Config::GetInstance().ServerPort); - - if(Config::GetInstance().UsePlexAccount) { - GetServer(Config::GetInstance().s_serverHost, Config::GetInstance().ServerPort)->SetAuthToken(Plexservice::GetMyPlexToken()); - } - } - - // Get remote Resources - Plexservice::UpdateResources(); - - char buffer[1024]; - m_registrationIsRunning = true; - m_discoveryIsRunning = true; - cMutexLock lock(&m_mutex); - - Poco::Net::MulticastSocket update_sock(Poco::Net::SocketAddress(Poco::Net::IPAddress(), _clientUpdatePort), true); - - update_sock.setLoopback(true); - update_sock.setReuseAddress(true); - update_sock.setTimeToLive(255); - update_sock.setBlocking(false); - - while(Running()) { - try { - if(!_helloSent) { - // Send initial Client Registration - std::string s = Poco::format("HELLO %s\n%s", _clientHeader, _clientData); - update_sock.sendTo(s.c_str(), s.length(), m_clientRegisterGroup, 0); - _helloSent = true; - } - if(m_registrationIsRunning) { - Poco::Net::SocketAddress sender; - int n = 0; - try { - n = update_sock.receiveFrom(buffer, sizeof(buffer), sender); - } catch(Poco::TimeoutException& e) { - n = 0; - } - if(n > 0) { - std::string buf(buffer, n); - if(buf.find("M-SEARCH * HTTP/1.") != std::string::npos) { - //dsyslog("[plex]: Detected client discovery request from %s", sender.host().toString().c_str()); - int t = std::time(0); - std::string s = Poco::format("HTTP/1.0 200 OK\r\n%sUpdated-At: %d", _clientData, t); - update_sock.sendTo(s.c_str(), s.length(), sender, 0); - m_clientRegistered = true; - } - } - } - - } catch(Poco::IOException&) { - // networkconnection is lost, reset - _helloSent = false; - } catch (Poco::Exception&) { - - } - - if(m_discoveryIsRunning && _discoverTimer.TimedOut()) { - discover(); - _discoverTimer.Set(_discoverInterval); - } - m_waitCondition.TimedWait(m_mutex, 500); - } - // Client loop stopped - try { - // unregister from Server - std::string s = Poco::format("BYE %s\r\n%s", _clientHeader, _clientData); - update_sock.sendTo(s.c_str(), s.length(), m_clientRegisterGroup, 0); - } catch (Poco::Exception) {} - - m_clientRegistered = false; -} - -void plexgdm::discover() -{ - try { - - - char buffer[1024]; - std::map<std::string, std::string> vBuffer; - - Poco::Net::MulticastSocket socket(Poco::Net::SocketAddress(Poco::Net::IPAddress(), m_discoverAdress.port()), true); - socket.setLoopback(true); - socket.setTimeToLive(1); - socket.setReceiveTimeout(Poco::Timespan(0, 600 * 1000)); // microseconds - socket.joinGroup(m_discoverAdress.host()); // Throws a NotFoundException if there is no multicast network device - socket.sendTo(_discoverMessage.c_str(), _discoverMessage.length(), m_discoverAdress, 0); - - try { - - while(true) { - Poco::Net::SocketAddress sender; - int n = socket.receiveFrom(buffer, sizeof(buffer), sender); - std::string buf(buffer, n); - if(buf.find("200 OK") != std::string::npos) { - vBuffer[sender.host().toString()] = buf; - } - } - - } catch(Poco::TimeoutException) {} - - socket.close(); - - m_discoveryComplete = true; - - for(std::map<std::string, std::string>::iterator it = vBuffer.begin(); it != vBuffer.end(); ++it) { - std::string host = it->first; - std::string data = it->second; - - PlexServer newServ(data, host); - // Set token for local servers - if(Config::GetInstance().UsePlexAccount) { - newServ.SetAuthToken(Plexservice::GetMyPlexToken()); - } - - if(AddServer(newServ)) { - isyslog("[plex] New server found via GDM: %s", host.c_str()); - } - else if(GetServer(newServ.m_sUuid)) { - GetServer(newServ.m_sUuid)->ParseData(data, host); - dsyslog("[plex] Server updated via GDM: %s", host.c_str()); - } - } - } catch (Poco::IOException&) { - // No Networkconnection - } catch(Poco::NotFoundException&) { - // there is no multicast network device - } catch (Poco::Exception&) {} -} - -void plexgdm::stopRegistration() -{ - if(m_registrationIsRunning) { - m_registrationIsRunning = false; - m_waitCondition.Broadcast(); - Cancel(); - } -} - -PlexServer* plexgdm::GetServer(std::string ip, int port) -{ - for(std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { - if(s_it->GetHost() == ip && s_it->GetPort() == port) { - return &(*s_it); - } - } - m_vServers.push_back(PlexServer(ip, port)); - return &m_vServers[m_vServers.size()-1]; -} +namespace plexclient { + + plexgdm::plexgdm() { + _discoverMessage = "M-SEARCH * HTTP/1.0"; + _clientHeader = "* HTTP/1.0"; + _multicastAddress = "239.0.0.250"; + _clientUpdatePort = 32412; + _helloSent = false; + _discoverInterval = 30 * 1000; + _discoverTimer.Set(1); + + m_discoverAdress = Poco::Net::SocketAddress(_multicastAddress, 32414); + m_clientRegisterGroup = Poco::Net::SocketAddress(_multicastAddress, 32413); + + m_discoveryComplete = false; + m_registrationIsRunning = false; + m_clientRegistered = false; + m_discoveryInterval = 120; + m_discoveryIsRunning = false; + } + + plexgdm::~plexgdm() { + } + + void plexgdm::clientDetails(std::string c_id, + std::string c_name, + std::string c_port, + std::string c_product, + std::string c_version) { + _clientData = "Content-Type: plex/media-player\r\n" + "Resource-Identifier: " + c_id + "\r\n" + "Device-Class: PC\r\n" + "Name: " + c_name + "\r\n" + "Port: " + c_port + "\r\n" + "Product: " + c_product + "\r\n" + "Protocol: plex\r\n" + "Protocol-Capabilities: navigation,playback,timeline\r\n" + "Protocol-Version: 1\r\n" + "Version: " + c_version + "\r\n"; + _clientId = c_id; + } + + std::string plexgdm::getClientDetails() { + if (_clientData.empty()) + throw "client_Data not initialized"; + return _clientData; + } + + void plexgdm::Action() { + if (Config::GetInstance().UseConfiguredServer) { + // Adds a Server to vector + GetServer(Config::GetInstance().s_serverHost, Config::GetInstance().ServerPort); + + if (Config::GetInstance().UsePlexAccount) { + GetServer(Config::GetInstance().s_serverHost, Config::GetInstance().ServerPort)->SetAuthToken( + Plexservice::GetMyPlexToken()); + } + } + + // Get remote Resources + Plexservice::UpdateResources(); + + char buffer[1024]; + m_registrationIsRunning = true; + m_discoveryIsRunning = true; + cMutexLock lock(&m_mutex); + + Poco::Net::MulticastSocket update_sock(Poco::Net::SocketAddress(Poco::Net::IPAddress(), _clientUpdatePort), + true); + + update_sock.setLoopback(true); + update_sock.setReuseAddress(true); + update_sock.setTimeToLive(255); + update_sock.setBlocking(false); + + while (Running()) { + try { + if (!_helloSent) { + // Send initial Client Registration + std::string s = Poco::format("HELLO %s\n%s", _clientHeader, _clientData); + update_sock.sendTo(s.c_str(), s.length(), m_clientRegisterGroup, 0); + _helloSent = true; + } + if (m_registrationIsRunning) { + Poco::Net::SocketAddress sender; + int n = 0; + try { + n = update_sock.receiveFrom(buffer, sizeof(buffer), sender); + } catch (Poco::TimeoutException &e) { + n = 0; + } + if (n > 0) { + std::string buf(buffer, n); + if (buf.find("M-SEARCH * HTTP/1.") != std::string::npos) { + //dsyslog("[plex]: Detected client discovery request from %s", sender.host().toString().c_str()); + int t = std::time(0); + std::string s = Poco::format("HTTP/1.0 200 OK\r\n%sUpdated-At: %d", _clientData, t); + update_sock.sendTo(s.c_str(), s.length(), sender, 0); + m_clientRegistered = true; + } + } + } + + } catch (Poco::IOException &) { + // networkconnection is lost, reset + _helloSent = false; + } catch (Poco::Exception &) { + + } + + if (m_discoveryIsRunning && _discoverTimer.TimedOut()) { + discover(); + _discoverTimer.Set(_discoverInterval); + } + m_waitCondition.TimedWait(m_mutex, 500); + } + // Client loop stopped + try { + // unregister from Server + std::string s = Poco::format("BYE %s\r\n%s", _clientHeader, _clientData); + update_sock.sendTo(s.c_str(), s.length(), m_clientRegisterGroup, 0); + } catch (Poco::Exception) { } + + m_clientRegistered = false; + } + + void plexgdm::discover() { + try { + + + char buffer[1024]; + std::map<std::string, std::string> vBuffer; + + Poco::Net::MulticastSocket socket(Poco::Net::SocketAddress(Poco::Net::IPAddress(), m_discoverAdress.port()), + true); + socket.setLoopback(true); + socket.setTimeToLive(1); + socket.setReceiveTimeout(Poco::Timespan(0, 600 * 1000)); // microseconds + socket.joinGroup( + m_discoverAdress.host()); // Throws a NotFoundException if there is no multicast network device + socket.sendTo(_discoverMessage.c_str(), _discoverMessage.length(), m_discoverAdress, 0); + + try { + + while (true) { + Poco::Net::SocketAddress sender; + int n = socket.receiveFrom(buffer, sizeof(buffer), sender); + std::string buf(buffer, n); + if (buf.find("200 OK") != std::string::npos) { + vBuffer[sender.host().toString()] = buf; + } + } + + } catch (Poco::TimeoutException) { } + + socket.close(); + + m_discoveryComplete = true; + + for (std::map<std::string, std::string>::iterator it = vBuffer.begin(); it != vBuffer.end(); ++it) { + std::string host = it->first; + std::string data = it->second; + + PlexServer newServ(data, host); + // Set token for local servers + if (Config::GetInstance().UsePlexAccount) { + newServ.SetAuthToken(Plexservice::GetMyPlexToken()); + } + + if (AddServer(newServ)) { + isyslog("[plex] New server found via GDM: %s", host.c_str()); + } + else if (GetServer(newServ.m_sUuid)) { + GetServer(newServ.m_sUuid)->ParseData(data, host); + dsyslog("[plex] Server updated via GDM: %s", host.c_str()); + } + } + } catch (Poco::IOException &) { + // No Networkconnection + } catch (Poco::NotFoundException &) { + // there is no multicast network device + } catch (Poco::Exception &) { } + } + + void plexgdm::stopRegistration() { + if (m_registrationIsRunning) { + m_registrationIsRunning = false; + m_waitCondition.Broadcast(); + Cancel(); + } + } + + PlexServer *plexgdm::GetServer(std::string ip, int port) { + for (std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { + if (s_it->GetHost() == ip && s_it->GetPort() == port) { + return &(*s_it); + } + } + m_vServers.push_back(PlexServer(ip, port)); + return &m_vServers[m_vServers.size() - 1]; + } /* * Returns the first owned online server, if there is no owned server it will return the first remote server, or NULL */ -PlexServer* plexgdm::GetFirstServer() -{ - for(std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { - if(s_it->IsOwned() && !s_it->Offline) { - return &(*s_it); - } - } - if (m_vServers.size() > 0) return &m_vServers[0]; - return NULL; -} - -PlexServer* plexgdm::GetServer(std::string uuid) -{ - for(std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { - if(s_it->GetUuid() == uuid ){ - return &(*s_it); - } - } - return NULL; -} - -bool plexgdm::AddServer(PlexServer server) -{ - for(std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { - if(s_it->GetUuid() == server.GetUuid() ){ - return false; - } - } - m_vServers.push_back(server); - isyslog("[plex] New Server Added: %s", server.GetUri().c_str()); - return true; -} + PlexServer *plexgdm::GetFirstServer() { + for (std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { + if (s_it->IsOwned() && !s_it->Offline) { + return &(*s_it); + } + } + if (m_vServers.size() > 0) return &m_vServers[0]; + return NULL; + } + + PlexServer *plexgdm::GetServer(std::string uuid) { + for (std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { + if (s_it->GetUuid() == uuid) { + return &(*s_it); + } + } + return NULL; + } + + bool plexgdm::AddServer(PlexServer server) { + for (std::vector<PlexServer>::iterator s_it = m_vServers.begin(); s_it != m_vServers.end(); ++s_it) { + if (s_it->GetUuid() == server.GetUuid()) { + return false; + } + } + m_vServers.push_back(server); + isyslog("[plex] New Server Added: %s", server.GetUri().c_str()); + return true; + } } // namespace @@ -19,62 +19,70 @@ #include "PlexServer.h" -namespace plexclient -{ - -class plexgdm : public cThread -{ -public: - static plexgdm& GetInstance() { - static plexgdm instance; - return instance; - } - ~plexgdm(); - void clientDetails(std::string c_id, std::string c_name, std::string c_port, std::string c_product, std::string c_version); - std::string getClientDetails(); - PlexServer* GetServer(std::string ip, int port); - PlexServer* GetServer(std::string uuid); - bool AddServer(PlexServer server); - PlexServer* GetFirstServer(); - void discover(); - - void Action(void); - - void stopRegistration(); - - std::vector<PlexServer> &GetPlexservers() { - return m_vServers; - } - -protected: - - -private: - plexgdm(); - cMutex m_mutex; - cCondVar m_waitCondition; - int _discoverInterval; - cTimeMs _discoverTimer; - bool _helloSent; - - Poco::Net::SocketAddress m_discoverAdress; - Poco::Net::SocketAddress m_clientRegisterGroup; - - volatile int m_discoveryInterval; - - volatile bool m_discoveryComplete; - volatile bool m_clientRegistered; - volatile bool m_discoveryIsRunning; - volatile bool m_registrationIsRunning; - - std::string _discoverMessage; - std::string _clientHeader; - std::string _clientData; - std::string _clientId; - std::string _multicastAddress; - int _clientUpdatePort; - std::vector<PlexServer> m_vServers; -}; +namespace plexclient { + + class plexgdm : public cThread { + public: + static plexgdm &GetInstance() { + static plexgdm instance; + return instance; + } + + ~plexgdm(); + + void clientDetails(std::string c_id, std::string c_name, std::string c_port, std::string c_product, + std::string c_version); + + std::string getClientDetails(); + + PlexServer *GetServer(std::string ip, int port); + + PlexServer *GetServer(std::string uuid); + + bool AddServer(PlexServer server); + + PlexServer *GetFirstServer(); + + void discover(); + + void Action(void); + + void stopRegistration(); + + std::vector<PlexServer> &GetPlexservers() { + return m_vServers; + } + + protected: + + + private: + plexgdm(); + + cMutex m_mutex; + cCondVar m_waitCondition; + int _discoverInterval; + cTimeMs _discoverTimer; + bool _helloSent; + + Poco::Net::SocketAddress m_discoverAdress; + Poco::Net::SocketAddress m_clientRegisterGroup; + + volatile int m_discoveryInterval; + + volatile bool m_discoveryComplete; + volatile bool m_clientRegistered; + volatile bool m_discoveryIsRunning; + volatile bool m_registrationIsRunning; + + std::string _discoverMessage; + std::string _clientHeader; + std::string _clientData; + std::string _clientId; + std::string _multicastAddress; + int _clientUpdatePort; + std::vector<PlexServer> m_vServers; + }; } #endif // PLEXGDM_H @@ -4,20 +4,17 @@ #define MPV_SEEK "Mpv_Seek" // play the given Filename, this can be a media file or a playlist -typedef struct -{ - char *Filename; +typedef struct { + char *Filename; } Mpv_PlayFile; // Overrides the displayed title in replay info -typedef struct -{ - char *Title; +typedef struct { + char *Title; } Mpv_SetTitle; -typedef struct -{ - int SeekAbsolute; - int SeekRelative; +typedef struct { + int SeekAbsolute; + int SeekRelative; } Mpv_Seek;
\ No newline at end of file diff --git a/tokendefinitions.h b/tokendefinitions.h index e4e9d0a..dffdc46 100644 --- a/tokendefinitions.h +++ b/tokendefinitions.h @@ -2,198 +2,198 @@ #define __TOKENDEFINITIONS_H enum class eViews { - rootView, - detailView + rootView, + detailView }; enum class eViewElementsDetail { - background, - footer, - info, - message, - scrollbar, - watch + background, + footer, + info, + message, + scrollbar, + watch }; enum class eViewElementsRoot { - background, - header, - footer, - infopane, - watch, - message, - scrollbar + background, + header, + footer, + infopane, + watch, + message, + scrollbar }; enum class eViewGrids { - cover, - detail, - list, + cover, + detail, + list, }; enum class eViewDetailViewGrids { - extras + extras }; enum class eTokenGridInt { - viewmode = 0, - viewgroup, - viewCount, - viewoffset, - viewoffsetpercent, - duration, - year, - hasthumb, - hasart, - ismovie, - isepisode, - isdirectory, - isshow, - isseason, - isclip, - originallyAvailableYear, - originallyAvailableMonth, - originallyAvailableDay, - season, - episode, - leafCount, - viewedLeafCount, - childCount, - rating, - hasseriesthumb, - hasbanner, - columns, - rows, - position, - totalcount, - bitrate, - width, - height, - audioChannels, - isdummy, - isserver, - serverport, - extratype + viewmode = 0, + viewgroup, + viewCount, + viewoffset, + viewoffsetpercent, + duration, + year, + hasthumb, + hasart, + ismovie, + isepisode, + isdirectory, + isshow, + isseason, + isclip, + originallyAvailableYear, + originallyAvailableMonth, + originallyAvailableDay, + season, + episode, + leafCount, + viewedLeafCount, + childCount, + rating, + hasseriesthumb, + hasbanner, + columns, + rows, + position, + totalcount, + bitrate, + width, + height, + audioChannels, + isdummy, + isserver, + serverport, + extratype }; enum class eTokenGridStr { - title = 0, - orginaltitle, - summary, - tagline, - contentrating, - ratingstring, - studio, - thumb, - art, - seriestitle, - seriesthumb, - banner, - videoResolution, - aspectRatio, - audioCodec, - videoCodec, - container, - videoFrameRate, - serverstartpointname, - serverip, - serverversion, - tabname + title = 0, + orginaltitle, + summary, + tagline, + contentrating, + ratingstring, + studio, + thumb, + art, + seriestitle, + seriesthumb, + banner, + videoResolution, + aspectRatio, + audioCodec, + videoCodec, + container, + videoFrameRate, + serverstartpointname, + serverip, + serverversion, + tabname }; enum class eTokenGridActorLst { - roles = 0 + roles = 0 }; enum class eTokenGridGenresLst { - genres = 0 + genres = 0 }; - + enum class eTokenMessageInt { - displaymessage = 0 + displaymessage = 0 }; enum class eTokenMessageStr { - message = 0 + message = 0 }; enum class eTokenScrollbarInt { - height = 0, - offset, - hasscrollbar + height = 0, + offset, + hasscrollbar }; enum class eTokenBackgroundInt { - viewmode = 0, - isdirectory + viewmode = 0, + isdirectory }; enum class eTokenBackgroundStr { - selecteditembackground = 0, - currentdirectorybackground + selecteditembackground = 0, + currentdirectorybackground }; enum class eTokenDetailBackgroundInt { - hasfanart = 0, - hascover + hasfanart = 0, + hascover }; enum class eTokenDetailBackgroundStr { - fanartpath = 0, - coverpath + fanartpath = 0, + coverpath }; enum class eTokenTimeInt { - sec = 0, - min, - hour, - hmins, - day, - year + sec = 0, + min, + hour, + hmins, + day, + year }; enum class eTokenTimeStr { - time = 0, - dayname, - daynameshort, - dayleadingzero, - month, - monthname, - monthnameshort + time = 0, + dayname, + daynameshort, + dayleadingzero, + month, + monthname, + monthnameshort }; enum class eTokenFooterInt { - red1 = 0, - red2, - red3, - red4, - green1, - green2, - green3, - green4, - yellow1, - yellow2, - yellow3, - yellow4, - blue1, - blue2, - blue3, - blue4 + red1 = 0, + red2, + red3, + red4, + green1, + green2, + green3, + green4, + yellow1, + yellow2, + yellow3, + yellow4, + blue1, + blue2, + blue3, + blue4 }; enum class eTokenFooterStr { - red = 0, - green, - yellow, - blue + red = 0, + green, + yellow, + blue }; enum class eTokenProgressbarInt { - + }; enum class eTokenProgressbarStr { - + }; /*<TranscodeSession key="jhul52ltx5lpiudi" @@ -215,7 +215,7 @@ enum class eTokenProgressbarStr { * height="808" /> */ enum class eTokenTranscodeinfoStr { - + }; #endif //__TOKENDEFINITIONS_H
\ No newline at end of file @@ -1,31 +1,29 @@ #include "user.h" -namespace plexclient -{ +namespace plexclient { -user::user(std::istream *response) -{ - try { - InputSource src(*response); - DOMParser parser; - Poco::XML::AutoPtr<Document> pDoc = parser.parse(&src); + user::user(std::istream *response) { + try { + InputSource src(*response); + DOMParser parser; + Poco::XML::AutoPtr<Document> pDoc = parser.parse(&src); - NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL); - Node* pNode = it.nextNode(); + NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ALL); + Node *pNode = it.nextNode(); - while(pNode) { - if(Poco::icompare(pNode->nodeName(),"authentication-token") == 0) { - pNode = it.nextNode(); - authenticationToken = pNode->nodeValue(); - break; - } - pNode = it.nextNode(); - } + while (pNode) { + if (Poco::icompare(pNode->nodeName(), "authentication-token") == 0) { + pNode = it.nextNode(); + authenticationToken = pNode->nodeValue(); + break; + } + pNode = it.nextNode(); + } - } catch(Exception &exc) { - std::cerr << exc.displayText() << std::endl; - } + } catch (Exception &exc) { + std::cerr << exc.displayText() << std::endl; + } -} + } } @@ -20,20 +20,18 @@ using Poco::XML::Node; using Poco::XML::AutoPtr; using Poco::Exception; -namespace plexclient -{ +namespace plexclient { -class user -{ -public: - user(std::istream *response); + class user { + public: + user(std::istream *response); - std::string authenticationToken; + std::string authenticationToken; -protected: + protected: -private: -}; + private: + }; } diff --git a/viewGridNavigator.cpp b/viewGridNavigator.cpp index 804e39d..8bd5b5b 100644 --- a/viewGridNavigator.cpp +++ b/viewGridNavigator.cpp @@ -6,272 +6,258 @@ unsigned int cGridElement::AbsoluteGridIdCounter = 0; -cGridElement::cGridElement() -{ - m_iGridId = AbsoluteGridIdCounter++; - Position = -1; - m_bInit = true; +cGridElement::cGridElement() { + m_iGridId = AbsoluteGridIdCounter++; + Position = -1; + m_bInit = true; } -cViewGridNavigator::cViewGridNavigator(std::shared_ptr<skindesignerapi::cOsdView> rootView) -{ - m_columns = 2; - m_rows = 2; - m_startIndex = 0; - m_endIndex = 0; - m_newDimensions = true; - m_setIterator = true; - m_bEnableRedraw = false; - - m_pGrid = NULL; - m_pRootView = rootView; +cViewGridNavigator::cViewGridNavigator(std::shared_ptr<skindesignerapi::cOsdView> rootView) { + m_columns = 2; + m_rows = 2; + m_startIndex = 0; + m_endIndex = 0; + m_newDimensions = true; + m_setIterator = true; + m_bEnableRedraw = false; + + m_pGrid = NULL; + m_pRootView = rootView; } -void cViewGridNavigator::SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid> grid) -{ - if (grid) { - if(m_pGrid) m_pGrid->Clear(); - m_pGrid = std::shared_ptr<skindesignerapi::cViewGrid>(grid); - } +void cViewGridNavigator::SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid> grid) { + if (grid) { + if (m_pGrid) m_pGrid->Clear(); + m_pGrid = std::shared_ptr<skindesignerapi::cViewGrid>(grid); + } } -void cViewGridNavigator::ReDraw(cGridElement* element) -{ - if(m_bHidden || !m_bEnableRedraw) return; - if(element) { - cMutexLock MutexLock(&cPlexSdOsd::RedrawMutex); - if (!element->IsVisible()) { - return; - } - double x, y; - element->GetPosition(x, y); - element->AddTokens(m_pGrid); - m_pGrid->AddIntToken((int)eTokenGridInt::columns, m_columns); - m_pGrid->AddIntToken((int)eTokenGridInt::rows, m_rows); - double width = 1.0 / m_columns; - double height = 1.0 / m_rows; - m_pGrid->SetGrid(element->GridElementId(), x, y, width, height); - Flush(); - } +void cViewGridNavigator::ReDraw(cGridElement *element) { + if (m_bHidden || !m_bEnableRedraw) return; + if (element) { + cMutexLock MutexLock(&cPlexSdOsd::RedrawMutex); + if (!element->IsVisible()) { + return; + } + double x, y; + element->GetPosition(x, y); + element->AddTokens(m_pGrid); + m_pGrid->AddIntToken((int) eTokenGridInt::columns, m_columns); + m_pGrid->AddIntToken((int) eTokenGridInt::rows, m_rows); + double width = 1.0 / m_columns; + double height = 1.0 / m_rows; + m_pGrid->SetGrid(element->GridElementId(), x, y, width, height); + Flush(); + } } -void cViewGridNavigator::FilterElements(int scrollOffset) -{ - if(m_vElements.size() == 0) return; - - m_startIndex += scrollOffset; - if(m_startIndex < 0) m_startIndex = 0; - - m_endIndex = m_startIndex + (m_rows * m_columns); - if(m_endIndex > (int)m_vElements.size()) m_endIndex = m_vElements.size(); - - if(scrollOffset > 0 && m_startIndex >= m_endIndex) { - // allign elements - int delta = m_vElements.size() % m_columns; - delta = m_rows * m_columns - m_columns + delta; - m_startIndex = m_endIndex - delta; - } - - int i = 0; - int pos = 0; - m_bEnableRedraw = false; - for(auto it = m_vElements.begin(); it != m_vElements.end(); ++it) { - - if(i >= m_startIndex && i < m_endIndex) { - cGridElement *elem = *it; - elem->Position = pos++; - SetGridElementData(elem); - - if(m_setIterator) { - m_activeElementIter = it; - m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), true); - m_setIterator = false; - } - } else { - if((*it)->Position > -1) m_pGrid->Delete((*it)->GridElementId()); - (*it)->Dirty(); - (*it)->Position = -1; - (*it)->SetPosition(-1,-1); - } - i++; - } - m_bEnableRedraw = true; - m_newDimensions = false; +void cViewGridNavigator::FilterElements(int scrollOffset) { + if (m_vElements.size() == 0) return; + + m_startIndex += scrollOffset; + if (m_startIndex < 0) m_startIndex = 0; + + m_endIndex = m_startIndex + (m_rows * m_columns); + if (m_endIndex > (int) m_vElements.size()) m_endIndex = m_vElements.size(); + + if (scrollOffset > 0 && m_startIndex >= m_endIndex) { + // allign elements + int delta = m_vElements.size() % m_columns; + delta = m_rows * m_columns - m_columns + delta; + m_startIndex = m_endIndex - delta; + } + + int i = 0; + int pos = 0; + m_bEnableRedraw = false; + for (auto it = m_vElements.begin(); it != m_vElements.end(); ++it) { + + if (i >= m_startIndex && i < m_endIndex) { + cGridElement *elem = *it; + elem->Position = pos++; + SetGridElementData(elem); + + if (m_setIterator) { + m_activeElementIter = it; + m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), true); + m_setIterator = false; + } + } else { + if ((*it)->Position > -1) m_pGrid->Delete((*it)->GridElementId()); + (*it)->Dirty(); + (*it)->Position = -1; + (*it)->SetPosition(-1, -1); + } + i++; + } + m_bEnableRedraw = true; + m_newDimensions = false; } -void cViewGridNavigator::SetGridElementData(cGridElement *obj) -{ - // calculate position - double row, column, x, y, height, width; - - row = floor(obj->Position / m_columns); - column = obj->Position - (row * m_columns); - width = 1.0 / m_columns; - height = 1.0 / m_rows; - x = width * column; - y= height * row; - - cMutexLock MutexLock(&cPlexSdOsd::RedrawMutex); - if(obj->IsNew() || m_newDimensions) { - // fill data - obj->SetPosition(x, y); - obj->AddTokens(m_pGrid, true, std::bind(&cViewGridNavigator::ReDraw, this, std::placeholders::_1)); - // set GridDimensions - m_pGrid->AddIntToken((int)eTokenGridInt::columns, m_columns); - m_pGrid->AddIntToken((int)eTokenGridInt::rows, m_rows); - m_pGrid->AddIntToken((int)eTokenGridInt::position, obj->AbsolutePosition); - m_pGrid->AddIntToken((int)eTokenGridInt::totalcount, m_vElements.size()); - m_pGrid->SetGrid(obj->GridElementId(), x, y, width, height); - obj->InitFinished(); - } else { - obj->SetPosition(x, y); - m_pGrid->MoveGrid(obj->GridElementId(), x, y, width, height); - } +void cViewGridNavigator::SetGridElementData(cGridElement *obj) { + // calculate position + double row, column, x, y, height, width; + + row = floor(obj->Position / m_columns); + column = obj->Position - (row * m_columns); + width = 1.0 / m_columns; + height = 1.0 / m_rows; + x = width * column; + y = height * row; + + cMutexLock MutexLock(&cPlexSdOsd::RedrawMutex); + if (obj->IsNew() || m_newDimensions) { + // fill data + obj->SetPosition(x, y); + obj->AddTokens(m_pGrid, true, std::bind(&cViewGridNavigator::ReDraw, this, std::placeholders::_1)); + // set GridDimensions + m_pGrid->AddIntToken((int) eTokenGridInt::columns, m_columns); + m_pGrid->AddIntToken((int) eTokenGridInt::rows, m_rows); + m_pGrid->AddIntToken((int) eTokenGridInt::position, obj->AbsolutePosition); + m_pGrid->AddIntToken((int) eTokenGridInt::totalcount, m_vElements.size()); + m_pGrid->SetGrid(obj->GridElementId(), x, y, width, height); + obj->InitFinished(); + } else { + obj->SetPosition(x, y); + m_pGrid->MoveGrid(obj->GridElementId(), x, y, width, height); + } } -cGridElement* cViewGridNavigator::SelectedObject() -{ - if(!m_setIterator) - return *m_activeElementIter; - return NULL; +cGridElement *cViewGridNavigator::SelectedObject() { + if (!m_setIterator) + return *m_activeElementIter; + return NULL; } -void cViewGridNavigator::SetGridDimensions(int rows, int columns) -{ - m_rows = rows; - m_columns = columns; - m_newDimensions = true; +void cViewGridNavigator::SetGridDimensions(int rows, int columns) { + m_rows = rows; + m_columns = columns; + m_newDimensions = true; } -bool cViewGridNavigator::NavigateDown() -{ - if (m_setIterator ) return false; - auto next = m_activeElementIter + m_columns; - - bool scrollallaround = false; - if (next >= m_vElements.end() && Config::GetInstance().ScrollAllAround) { - next = m_vElements.begin(); - scrollallaround = true; - } else if(next >= m_vElements.end()) { - next = m_activeElementIter; // stay at current element //m_vElements.end()-1; - return false; - } - - // scroll down? - if(!(*next)->IsVisible()) { - int scrolloffset = m_columns; - if(Config::GetInstance().ScrollByPage) { - scrolloffset = m_columns*m_rows; - } - if(scrollallaround) - scrolloffset = -((*m_activeElementIter)->AbsolutePosition); - - FilterElements(scrolloffset); - } - - m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); - m_pGrid->SetCurrent((*next)->GridElementId(), true); - m_activeElementIter = next; - return true; +bool cViewGridNavigator::NavigateDown() { + if (m_setIterator) return false; + auto next = m_activeElementIter + m_columns; + + bool scrollallaround = false; + if (next >= m_vElements.end() && Config::GetInstance().ScrollAllAround) { + next = m_vElements.begin(); + scrollallaround = true; + } else if (next >= m_vElements.end()) { + next = m_activeElementIter; // stay at current element //m_vElements.end()-1; + return false; + } + + // scroll down? + if (!(*next)->IsVisible()) { + int scrolloffset = m_columns; + if (Config::GetInstance().ScrollByPage) { + scrolloffset = m_columns * m_rows; + } + if (scrollallaround) + scrolloffset = -((*m_activeElementIter)->AbsolutePosition); + + FilterElements(scrolloffset); + } + + m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); + m_pGrid->SetCurrent((*next)->GridElementId(), true); + m_activeElementIter = next; + return true; } -bool cViewGridNavigator::NavigateUp() -{ - if (m_setIterator) return false; - auto next = m_activeElementIter - m_columns; - - bool scrollallaround = false; - if (next < m_vElements.begin() && Config::GetInstance().ScrollAllAround) { - next = m_vElements.end() - 1; - scrollallaround = true; - } else if(next < m_vElements.begin()) { - next = m_activeElementIter; // stay at current element //m_vElements.end()-1; - return false; - } - - //scroll up? - if(!(*next)->IsVisible()) { - int scrolloffset = -m_columns; - if(Config::GetInstance().ScrollByPage) { - scrolloffset = -m_columns*m_rows; - } - if(scrollallaround) - scrolloffset = m_vElements.size(); - - FilterElements(scrolloffset); - } - - m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); - m_pGrid->SetCurrent((*next)->GridElementId(), true); - m_activeElementIter = next; - return true; +bool cViewGridNavigator::NavigateUp() { + if (m_setIterator) return false; + auto next = m_activeElementIter - m_columns; + + bool scrollallaround = false; + if (next < m_vElements.begin() && Config::GetInstance().ScrollAllAround) { + next = m_vElements.end() - 1; + scrollallaround = true; + } else if (next < m_vElements.begin()) { + next = m_activeElementIter; // stay at current element //m_vElements.end()-1; + return false; + } + + //scroll up? + if (!(*next)->IsVisible()) { + int scrolloffset = -m_columns; + if (Config::GetInstance().ScrollByPage) { + scrolloffset = -m_columns * m_rows; + } + if (scrollallaround) + scrolloffset = m_vElements.size(); + + FilterElements(scrolloffset); + } + + m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); + m_pGrid->SetCurrent((*next)->GridElementId(), true); + m_activeElementIter = next; + return true; } -bool cViewGridNavigator::NavigateLeft() -{ - if (m_setIterator || m_activeElementIter == m_vElements.begin()) return false; - auto next = m_activeElementIter - 1; +bool cViewGridNavigator::NavigateLeft() { + if (m_setIterator || m_activeElementIter == m_vElements.begin()) return false; + auto next = m_activeElementIter - 1; - if (m_columns == 1) { - next = m_activeElementIter - m_rows; - FilterElements(-m_rows); - } + if (m_columns == 1) { + next = m_activeElementIter - m_rows; + FilterElements(-m_rows); + } - if(next < m_vElements.begin()) next = m_vElements.begin(); + if (next < m_vElements.begin()) next = m_vElements.begin(); - if(!(*next)->IsVisible()) { - auto temp = m_activeElementIter; - if(Config::GetInstance().ScrollByPage) - FilterElements(-m_columns*m_rows); - else - FilterElements(-m_columns); + if (!(*next)->IsVisible()) { + auto temp = m_activeElementIter; + if (Config::GetInstance().ScrollByPage) + FilterElements(-m_columns * m_rows); + else + FilterElements(-m_columns); - m_activeElementIter = temp; - } + m_activeElementIter = temp; + } - m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); - m_pGrid->SetCurrent((*next)->GridElementId(), true); - m_activeElementIter = next; - return true; + m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); + m_pGrid->SetCurrent((*next)->GridElementId(), true); + m_activeElementIter = next; + return true; } -bool cViewGridNavigator::NavigateRight() -{ - if (m_setIterator || m_activeElementIter == m_vElements.end() - 1) return false; - auto next = m_activeElementIter + 1; - - if (m_columns == 1) { - next = m_activeElementIter + m_rows; - FilterElements(m_rows); - } - - if(next >= m_vElements.end()) next = m_vElements.end()-1; - - if(!(*next)->IsVisible()) { - if(Config::GetInstance().ScrollByPage) - FilterElements(m_columns*m_rows); - else - FilterElements(m_columns); - } - - m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); - m_pGrid->SetCurrent((*next)->GridElementId(), true); - m_activeElementIter = next; - return true; +bool cViewGridNavigator::NavigateRight() { + if (m_setIterator || m_activeElementIter == m_vElements.end() - 1) return false; + auto next = m_activeElementIter + 1; + + if (m_columns == 1) { + next = m_activeElementIter + m_rows; + FilterElements(m_rows); + } + + if (next >= m_vElements.end()) next = m_vElements.end() - 1; + + if (!(*next)->IsVisible()) { + if (Config::GetInstance().ScrollByPage) + FilterElements(m_columns * m_rows); + else + FilterElements(m_columns); + } + + m_pGrid->SetCurrent((*m_activeElementIter)->GridElementId(), false); + m_pGrid->SetCurrent((*next)->GridElementId(), true); + m_activeElementIter = next; + return true; } -void cViewGridNavigator::Deactivate(bool hide) -{ - if (m_pRootView) { - m_pRootView->Deactivate(hide); - m_bHidden = hide; - } +void cViewGridNavigator::Deactivate(bool hide) { + if (m_pRootView) { + m_pRootView->Deactivate(hide); + m_bHidden = hide; + } } -void cViewGridNavigator::Activate() -{ - if (m_pRootView) { - m_pRootView->Activate(); - m_bHidden = false; - } +void cViewGridNavigator::Activate() { + if (m_pRootView) { + m_pRootView->Activate(); + m_bHidden = false; + } } diff --git a/viewGridNavigator.h b/viewGridNavigator.h index 4482d39..8cfd259 100644 --- a/viewGridNavigator.h +++ b/viewGridNavigator.h @@ -6,69 +6,100 @@ #include <functional> #include <libskindesignerapi/osdelements.h> -class cGridElement -{ +class cGridElement { private: - bool m_bInit; - double m_posX; - double m_posY; - static unsigned int AbsoluteGridIdCounter; + bool m_bInit; + double m_posX; + double m_posY; + static unsigned int AbsoluteGridIdCounter; protected: - unsigned int m_iGridId; + unsigned int m_iGridId; public: - cGridElement(); - - bool IsNew() { return m_bInit; }; + cGridElement(); + + bool IsNew() { return m_bInit; }; + void Dirty() { m_bInit = true; }; + void InitFinished() { m_bInit = false; }; - unsigned int GridElementId() { return m_iGridId; } - bool IsVisible() { return Position > -1; } - void SetPosition(double x, double y) { m_posX = x; m_posY = y; }; - void GetPosition(double &x, double &y) { x = m_posX; y = m_posY; }; - virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> osdElem, bool clear = true, std::function<void(cGridElement*)> OnCached = NULL) = 0; - int Position; - int AbsolutePosition; + + unsigned int GridElementId() { return m_iGridId; } + + bool IsVisible() { return Position > -1; } + + void SetPosition(double x, double y) { + m_posX = x; + m_posY = y; + }; + + void GetPosition(double &x, double &y) { + x = m_posX; + y = m_posY; + }; + + virtual void AddTokens(std::shared_ptr<skindesignerapi::cOsdElement> osdElem, bool clear = true, + std::function<void(cGridElement *)> OnCached = NULL) = 0; + + int Position; + int AbsolutePosition; }; -class cViewGridNavigator -{ +class cViewGridNavigator { protected: - int m_rows; - int m_columns; - bool m_bHidden; - bool m_bEnableRedraw; - - std::shared_ptr<skindesignerapi::cOsdView> m_pRootView; - std::shared_ptr<skindesignerapi::cViewGrid> m_pGrid; - - bool m_newDimensions; - bool m_setIterator; - std::vector<cGridElement*> m_vElements; - std::vector<cGridElement*>::iterator m_activeElementIter; - int m_startIndex; - int m_endIndex; - - void FilterElements(int scrollOffset); - void SetGridElementData(cGridElement *obj); - void SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid> grid); - + int m_rows; + int m_columns; + bool m_bHidden; + bool m_bEnableRedraw; + + std::shared_ptr<skindesignerapi::cOsdView> m_pRootView; + std::shared_ptr<skindesignerapi::cViewGrid> m_pGrid; + + bool m_newDimensions; + bool m_setIterator; + std::vector<cGridElement *> m_vElements; + std::vector<cGridElement *>::iterator m_activeElementIter; + int m_startIndex; + int m_endIndex; + + void FilterElements(int scrollOffset); + + void SetGridElementData(cGridElement *obj); + + void SetViewGrid(std::shared_ptr<skindesignerapi::cViewGrid> grid); + public: - cViewGridNavigator(std::shared_ptr<skindesignerapi::cOsdView> rootView); - void SetGridDimensions(int rows, int columns); - virtual void Flush() { m_pGrid->Display(); m_pRootView->Display(); }; - virtual void Clear() = 0; - virtual bool NavigateLeft(); - virtual bool NavigateRight(); - virtual bool NavigateUp(); - virtual bool NavigateDown(); - virtual eOSState NavigateSelect() = 0; - virtual eOSState NavigateBack() = 0; - virtual void ReDraw(cGridElement* element); - cGridElement* SelectedObject(); - virtual void Deactivate(bool hide); - virtual void Activate(); + cViewGridNavigator(std::shared_ptr<skindesignerapi::cOsdView> rootView); + + void SetGridDimensions(int rows, int columns); + + virtual void Flush() { + m_pGrid->Display(); + m_pRootView->Display(); + }; + + virtual void Clear() = 0; + + virtual bool NavigateLeft(); + + virtual bool NavigateRight(); + + virtual bool NavigateUp(); + + virtual bool NavigateDown(); + + virtual eOSState NavigateSelect() = 0; + + virtual eOSState NavigateBack() = 0; + + virtual void ReDraw(cGridElement *element); + + cGridElement *SelectedObject(); + + virtual void Deactivate(bool hide); + + virtual void Activate(); }; #endif // cViewGridNAVIGATOR_H diff --git a/viewHeader.cpp b/viewHeader.cpp index 5d7c4ec..43d067e 100644 --- a/viewHeader.cpp +++ b/viewHeader.cpp @@ -1,54 +1,49 @@ #include "viewHeader.h" #include "tokendefinitions.h" -cViewHeader::cViewHeader(skindesignerapi::cViewElement* viewElem) -{ - m_pViewElem = std::shared_ptr<skindesignerapi::cViewElement>(viewElem); - m_eCurrentTab = ePlexMenuTab::pmtOnDeck; +cViewHeader::cViewHeader(skindesignerapi::cViewElement *viewElem) { + m_pViewElem = std::shared_ptr<skindesignerapi::cViewElement>(viewElem); + m_eCurrentTab = ePlexMenuTab::pmtOnDeck; } -cViewHeader::~cViewHeader() -{ +cViewHeader::~cViewHeader() { } -void cViewHeader::Draw(cGridElement* elem) -{ - m_pViewElem->Clear(); - m_pViewElem->ClearTokens(); - - elem->AddTokens(m_pViewElem, false); - - m_pViewElem->Display(); +void cViewHeader::Draw(cGridElement *elem) { + m_pViewElem->Clear(); + m_pViewElem->ClearTokens(); + + elem->AddTokens(m_pViewElem, false); + + m_pViewElem->Display(); } -ePlexMenuTab cViewHeader::NextTab() -{ - switch(m_eCurrentTab) { - case ePlexMenuTab::pmtOnDeck: - m_eCurrentTab = ePlexMenuTab::pmtRecentlyAdded; - break; - case ePlexMenuTab::pmtRecentlyAdded: - m_eCurrentTab = ePlexMenuTab::pmtLibrary; - break; - case ePlexMenuTab::pmtLibrary: - m_eCurrentTab = ePlexMenuTab::pmtOnDeck; - break; - } - return m_eCurrentTab; +ePlexMenuTab cViewHeader::NextTab() { + switch (m_eCurrentTab) { + case ePlexMenuTab::pmtOnDeck: + m_eCurrentTab = ePlexMenuTab::pmtRecentlyAdded; + break; + case ePlexMenuTab::pmtRecentlyAdded: + m_eCurrentTab = ePlexMenuTab::pmtLibrary; + break; + case ePlexMenuTab::pmtLibrary: + m_eCurrentTab = ePlexMenuTab::pmtOnDeck; + break; + } + return m_eCurrentTab; } -ePlexMenuTab cViewHeader::PrevTab() -{ - switch(m_eCurrentTab) { - case ePlexMenuTab::pmtOnDeck: - m_eCurrentTab = ePlexMenuTab::pmtLibrary; - break; - case ePlexMenuTab::pmtRecentlyAdded: - m_eCurrentTab = ePlexMenuTab::pmtOnDeck; - break; - case ePlexMenuTab::pmtLibrary: - m_eCurrentTab = ePlexMenuTab::pmtRecentlyAdded; - break; - } - return m_eCurrentTab; +ePlexMenuTab cViewHeader::PrevTab() { + switch (m_eCurrentTab) { + case ePlexMenuTab::pmtOnDeck: + m_eCurrentTab = ePlexMenuTab::pmtLibrary; + break; + case ePlexMenuTab::pmtRecentlyAdded: + m_eCurrentTab = ePlexMenuTab::pmtOnDeck; + break; + case ePlexMenuTab::pmtLibrary: + m_eCurrentTab = ePlexMenuTab::pmtRecentlyAdded; + break; + } + return m_eCurrentTab; } diff --git a/viewHeader.h b/viewHeader.h index 997f741..eac40bf 100644 --- a/viewHeader.h +++ b/viewHeader.h @@ -6,24 +6,28 @@ #include "viewGridNavigator.h" enum ePlexMenuTab { - pmtOnDeck, - pmtRecentlyAdded, - pmtLibrary + pmtOnDeck, + pmtRecentlyAdded, + pmtLibrary }; -class cViewHeader -{ +class cViewHeader { private: - ePlexMenuTab m_eCurrentTab; - std::shared_ptr<skindesignerapi::cViewElement> m_pViewElem; - + ePlexMenuTab m_eCurrentTab; + std::shared_ptr<skindesignerapi::cViewElement> m_pViewElem; + public: - cViewHeader(skindesignerapi::cViewElement* viewElem); - ~cViewHeader(); - void Draw(cGridElement* elem); - ePlexMenuTab NextTab(); - ePlexMenuTab PrevTab(); - ePlexMenuTab CurrentTab() { return m_eCurrentTab; } + cViewHeader(skindesignerapi::cViewElement *viewElem); + + ~cViewHeader(); + + void Draw(cGridElement *elem); + + ePlexMenuTab NextTab(); + + ePlexMenuTab PrevTab(); + + ePlexMenuTab CurrentTab() { return m_eCurrentTab; } }; #endif // CVIEWHEADER_H |