From 7b64bf5062f3eb6ddff5d7606e44367bd5077e4c Mon Sep 17 00:00:00 2001 From: chriszero Date: Tue, 15 Dec 2015 22:15:35 +0100 Subject: Added SSL support, started support for remote resources (servers). Browsing remote servers is working. plex.tv login is mandatory. --- Plexservice.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 14 deletions(-) (limited to 'Plexservice.cpp') diff --git a/Plexservice.cpp b/Plexservice.cpp index bae8ed2..3e08613 100644 --- a/Plexservice.cpp +++ b/Plexservice.cpp @@ -53,6 +53,7 @@ std::string Plexservice::GetMyPlexToken() // 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."); } @@ -74,7 +75,7 @@ void Plexservice::Authenticate() std::string token = GetMyPlexToken(); auto pRequest = CreateRequest("/?X-Plex-Token=" + token); - Poco::Net::HTTPClientSession session(pServer->GetIpAdress(), pServer->GetPort()); + Poco::Net::HTTPClientSession session(pServer->GetHost(), pServer->GetPort()); session.sendRequest(*pRequest); Poco::Net::HTTPResponse response; /*std::istream &rs = */ @@ -87,6 +88,37 @@ void Plexservice::Authenticate() } } +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 pContainer = GetMediaContainer("https://plex.tv/api/resources?includeHttps=1"); + + for(std::vector::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::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 remote server: %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; @@ -106,17 +138,18 @@ std::shared_ptr Plexservice::GetSection(std::string section, boo if(putOnStack) { m_vUriStack.push(uri); } - - Poco::Net::HTTPClientSession session(pServer->GetIpAdress(), pServer->GetPort()); - session.sendRequest(*pRequest); + + dsyslog("[plex] URI: %s%s", pServer->GetUri().c_str(), uri.c_str()); + //Poco::Net::HTTPClientSession session(pServer->GetHost(), pServer->GetPort()); + //session.sendRequest(*pRequest); + pServer->GetClientSession()->sendRequest(*pRequest); Poco::Net::HTTPResponse response; - std::istream &rs = session.receiveResponse(response); + std::istream &rs = pServer->GetClientSession()->receiveResponse(response); - dsyslog("[plex] URI: http://%s:%d%s", pServer->GetIpAdress().c_str(), pServer->GetPort(), uri.c_str()); std::shared_ptr pAllsections(new MediaContainer(&rs, pServer)); - session.abort(); + //session.abort(); return pAllsections; } catch (Poco::Net::NetException &exc) { @@ -153,8 +186,13 @@ std::unique_ptr Plexservice::CreateRequest(std::string p if(Config::GetInstance().UsePlexAccount) { // Add PlexToken to Header std::string token = GetMyPlexToken(); - if(!token.empty()) + 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; @@ -162,22 +200,58 @@ std::unique_ptr Plexservice::CreateRequest(std::string p std::shared_ptr Plexservice::GetMediaContainer(std::string fullUrl) { + Poco::Net::HTTPClientSession* pSession = NULL; try { Poco::URI fileuri(fullUrl); + + // Check for https + Poco::Net::Context::Ptr context = new Poco::Net::Context( + Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, // VERIFY_NONE...?! + 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); + + if(fileuri.getScheme().find("https") != std::string::npos) { + pSession = new Poco::Net::HTTPSClientSession(fileuri.getHost(), fileuri.getPort(), context); + } + else { + pSession = new Poco::Net::HTTPClientSession(fileuri.getHost(), fileuri.getPort()); + } + + // > HTTPS + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); PlexHelper::AddHttpHeader(request); + + if(Config::GetInstance().UsePlexAccount) { + // Add PlexToken to Header + std::string token = GetMyPlexToken(); + if(!token.empty()) + request.add("X-Plex-Token", token); + } - Poco::Net::HTTPClientSession session(fileuri.getHost(), fileuri.getPort()); - session.sendRequest(request); + pSession->sendRequest(request); Poco::Net::HTTPResponse response; - std::istream &rs = session.receiveResponse(response); - - std::shared_ptr pAllsections(new MediaContainer(&rs, plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()))); + std::istream &rs = pSession->receiveResponse(response); + + //Poco::StreamCopier::copyStream(rs, std::cout); + + std::shared_ptr pAllsections; + + // omit creating a server when talking to plex.tv + if(fileuri.getHost().find("plex.tv") != std::string::npos) { + pAllsections = std::shared_ptr(new MediaContainer(&rs)); + } + else { + pAllsections = std::shared_ptr(new MediaContainer(&rs, plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()))); + } + - session.abort(); + pSession->abort(); + delete pSession; return pAllsections; } catch (Poco::Net::NetException &exc) { + std::cout << exc.displayText() << std::endl; + delete pSession; return 0; } } -- cgit v1.2.3 From 1d624e296ee8b6a13abf0a4012a5e07b2354970e Mon Sep 17 00:00:00 2001 From: chriszero Date: Wed, 16 Dec 2015 21:02:47 +0100 Subject: Early remote server playback. Please test. --- Plexservice.cpp | 98 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 40 deletions(-) (limited to 'Plexservice.cpp') diff --git a/Plexservice.cpp b/Plexservice.cpp index 3e08613..3bb1c2a 100644 --- a/Plexservice.cpp +++ b/Plexservice.cpp @@ -97,11 +97,11 @@ void Plexservice::UpdateResources() return; // Plugin is used without plex.tv login } isyslog("[plex] Updating remote resources..."); - + std::shared_ptr pContainer = GetMediaContainer("https://plex.tv/api/resources?includeHttps=1"); - + for(std::vector::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? @@ -138,7 +138,7 @@ std::shared_ptr Plexservice::GetSection(std::string section, boo if(putOnStack) { m_vUriStack.push(uri); } - + dsyslog("[plex] URI: %s%s", pServer->GetUri().c_str(), uri.c_str()); //Poco::Net::HTTPClientSession session(pServer->GetHost(), pServer->GetPort()); //session.sendRequest(*pRequest); @@ -189,10 +189,10 @@ std::unique_ptr Plexservice::CreateRequest(std::string p if(pServer && !pServer->GetAuthToken().empty()) { pRequest->add("X-Plex-Token", pServer->GetAuthToken()); dsyslog("[plex] Using server access token"); - } - else if(!token.empty()) + } else if(!token.empty()) { pRequest->add("X-Plex-Token", token); dsyslog("[plex] Using global access token"); + } } return pRequest; @@ -201,57 +201,56 @@ std::unique_ptr Plexservice::CreateRequest(std::string p std::shared_ptr Plexservice::GetMediaContainer(std::string fullUrl) { Poco::Net::HTTPClientSession* pSession = NULL; + PlexServer* pServer = NULL; + bool ownSession = false; try { Poco::URI fileuri(fullUrl); - - // Check for https - Poco::Net::Context::Ptr context = new Poco::Net::Context( - Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, // VERIFY_NONE...?! - 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); - - if(fileuri.getScheme().find("https") != std::string::npos) { - pSession = new Poco::Net::HTTPSClientSession(fileuri.getHost(), fileuri.getPort(), context); + dsyslog("[plex] GetMediaContainer: %s", fullUrl.c_str()); + + if(fileuri.getHost().find("plex.tv") != std::string::npos) { + if(fileuri.getScheme().find("https") != std::string::npos) { + pSession = new Poco::Net::HTTPSClientSession(fileuri.getHost(), fileuri.getPort()); + } else { + pSession = new Poco::Net::HTTPClientSession(fileuri.getHost(), fileuri.getPort()); + } + ownSession = true; } else { - pSession = new Poco::Net::HTTPClientSession(fileuri.getHost(), fileuri.getPort()); + pServer = plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()); + pSession = pServer->GetClientSession(); } - // > HTTPS + + // > HTTPS + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); PlexHelper::AddHttpHeader(request); - + if(Config::GetInstance().UsePlexAccount) { // Add PlexToken to Header std::string token = GetMyPlexToken(); - if(!token.empty()) + if(pServer && !pServer->GetAuthToken().empty()) { + request.add("X-Plex-Token", pServer->GetAuthToken()); + dsyslog("[plex] Using server access token"); + } else if(!token.empty()) { request.add("X-Plex-Token", token); + dsyslog("[plex] Using global access token"); + } } pSession->sendRequest(request); Poco::Net::HTTPResponse response; std::istream &rs = pSession->receiveResponse(response); - + //Poco::StreamCopier::copyStream(rs, std::cout); - - std::shared_ptr pAllsections; - - // omit creating a server when talking to plex.tv - if(fileuri.getHost().find("plex.tv") != std::string::npos) { - pAllsections = std::shared_ptr(new MediaContainer(&rs)); - } - else { - pAllsections = std::shared_ptr(new MediaContainer(&rs, plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()))); - } - - pSession->abort(); - delete pSession; + std::shared_ptr pAllsections = std::shared_ptr(new MediaContainer(&rs, pServer)); + if (ownSession) delete pSession; return pAllsections; } catch (Poco::Net::NetException &exc) { std::cout << exc.displayText() << std::endl; - delete pSession; return 0; } } @@ -268,7 +267,12 @@ std::string Plexservice::GetUniversalTranscodeUrl(Video* video, int offset, Plex PlexServer* pSrv = server ? server : video->m_pServer; std::stringstream params; params << "/video/:/transcode/universal/start.m3u8?"; - params << "path=" << encode(pSrv->GetUri() + video->m_sKey); + // Force set localhost and http + Poco::URI pathUri(pSrv->GetUri()+video->m_sKey); + pathUri.setHost("127.0.0.1"); + pathUri.setScheme("http"); + + params << "path=" << encode(pathUri.toString()); params << "&mediaIndex=0"; params << "&partIndex=0"; params << "&protocol=hls"; @@ -276,23 +280,37 @@ std::string Plexservice::GetUniversalTranscodeUrl(Video* video, int offset, Plex params << "&fastSeek=0"; params << "&directPlay=0"; params << "&directStream=1"; - params << "&maxVideoBitrate=20000"; params << "&subtitles=burn"; //params << "&subtitleSize=90"; //params << "&skipSubtitles=1"; //params << "&audioBoost=100"; - params << "&videoResolution=1920x1080"; - params << "&videoQuality=100"; - params << "&session=" << encode(Config::GetInstance().GetUUID()); // TODO: generate Random SessionID + if(Config::GetInstance().UsePlexAccount) { + if(!pSrv->GetAuthToken().empty()) { + params << "&X-Plex-Token=" << pSrv->GetAuthToken(); + } + } + + if(pSrv->IsLocal()) { + params << "&videoResolution=1920x1080"; + params << "&maxVideoBitrate=20000"; + params << "&videoQuality=100"; + } else { + params << "&videoResolution=1280x720"; + params << "&maxVideoBitrate=8000"; + params << "&videoQuality=100"; + } + + params << "&session=" << encode(Config::GetInstance().GetUUID()); // TODO: generate Random SessionID + params << "&includeCodecs=1"; params << "©ts=1"; - + if(Config::GetInstance().UseAc3) { params << "&X-Plex-Client-Profile-Extra="; if(Config::GetInstance().UseAc3) params << encode("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)"); -- cgit v1.2.3 From 516d7da6bf79c8e48d5348706faeba8ea5061984 Mon Sep 17 00:00:00 2001 From: chriszero Date: Sat, 19 Dec 2015 21:55:26 +0100 Subject: Starting to redesign server communication. --- Plexservice.cpp | 142 ++++++++++++++++++++++---------------------------------- 1 file changed, 55 insertions(+), 87 deletions(-) (limited to 'Plexservice.cpp') diff --git a/Plexservice.cpp b/Plexservice.cpp index 3bb1c2a..1177c70 100644 --- a/Plexservice.cpp +++ b/Plexservice.cpp @@ -34,12 +34,9 @@ std::string Plexservice::GetMyPlexToken() b64.close(); std::string tempToken = ss.str(); - Poco::Net::Context::Ptr context = new Poco::Net::Context( - Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, // VERIFY_NONE...?! - 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); try { - Poco::Net::HTTPSClientSession plexSession("plex.tv", 443, context); + 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); @@ -98,7 +95,29 @@ void Plexservice::UpdateResources() } isyslog("[plex] Updating remote resources..."); - std::shared_ptr pContainer = GetMediaContainer("https://plex.tv/api/resources?includeHttps=1"); + + std::shared_ptr 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(new MediaContainer(&rs)); + + } catch (Poco::Net::NetException &exc) { + std::cout << exc.displayText() << std::endl; + return; + } for(std::vector::iterator d_it = pContainer->m_vDevices.begin(); d_it != pContainer->m_vDevices.end(); ++d_it) { @@ -140,16 +159,12 @@ std::shared_ptr Plexservice::GetSection(std::string section, boo } dsyslog("[plex] URI: %s%s", pServer->GetUri().c_str(), uri.c_str()); - //Poco::Net::HTTPClientSession session(pServer->GetHost(), pServer->GetPort()); - //session.sendRequest(*pRequest); - pServer->GetClientSession()->sendRequest(*pRequest); + Poco::Net::HTTPResponse response; - std::istream &rs = pServer->GetClientSession()->receiveResponse(response); - + std::istream &rs = pServer->MakeRequest(response, uri);; std::shared_ptr pAllsections(new MediaContainer(&rs, pServer)); - //session.abort(); return pAllsections; } catch (Poco::Net::NetException &exc) { @@ -200,122 +215,75 @@ std::unique_ptr Plexservice::CreateRequest(std::string p std::shared_ptr Plexservice::GetMediaContainer(std::string fullUrl) { - Poco::Net::HTTPClientSession* pSession = NULL; PlexServer* pServer = NULL; - bool ownSession = false; try { Poco::URI fileuri(fullUrl); dsyslog("[plex] GetMediaContainer: %s", fullUrl.c_str()); - if(fileuri.getHost().find("plex.tv") != std::string::npos) { - if(fileuri.getScheme().find("https") != std::string::npos) { - pSession = new Poco::Net::HTTPSClientSession(fileuri.getHost(), fileuri.getPort()); - } else { - pSession = new Poco::Net::HTTPClientSession(fileuri.getHost(), fileuri.getPort()); - } - ownSession = true; - } - else { - pServer = plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()); - pSession = pServer->GetClientSession(); - } + pServer = plexgdm::GetInstance().GetServer(fileuri.getHost(), fileuri.getPort()); - - - // > HTTPS - - Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, fileuri.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1); - PlexHelper::AddHttpHeader(request); - - if(Config::GetInstance().UsePlexAccount) { - // Add PlexToken to Header - std::string token = GetMyPlexToken(); - if(pServer && !pServer->GetAuthToken().empty()) { - request.add("X-Plex-Token", pServer->GetAuthToken()); - dsyslog("[plex] Using server access token"); - } else if(!token.empty()) { - request.add("X-Plex-Token", token); - dsyslog("[plex] Using global access token"); - } - } - - - pSession->sendRequest(request); Poco::Net::HTTPResponse response; - std::istream &rs = pSession->receiveResponse(response); + std::istream &rs = pServer->MakeRequest(response, fileuri.getPathAndQuery()); //Poco::StreamCopier::copyStream(rs, std::cout); std::shared_ptr pAllsections = std::shared_ptr(new MediaContainer(&rs, pServer)); - if (ownSession) delete pSession; return pAllsections; } catch (Poco::Net::NetException &exc) { std::cout << exc.displayText() << std::endl; return 0; } } - +/* std::string Plexservice::encode(std::string message) { std::string temp; Poco::URI::encode(message, " !\"#$%&'()*+,/:;=?@[]", temp); return temp; } - -std::string Plexservice::GetUniversalTranscodeUrl(Video* video, int offset, PlexServer* server) +*/ +std::string Plexservice::GetUniversalTranscodeUrl(Video* video, int offset, PlexServer* server, bool http) { PlexServer* pSrv = server ? server : video->m_pServer; - std::stringstream params; - params << "/video/:/transcode/universal/start.m3u8?"; + Poco::URI transcodeUri(pSrv->GetUri()); + transcodeUri.setPath("/video/:/transcode/universal/start.m3u8"); + // Force set localhost and http Poco::URI pathUri(pSrv->GetUri()+video->m_sKey); pathUri.setHost("127.0.0.1"); pathUri.setScheme("http"); - params << "path=" << encode(pathUri.toString()); - params << "&mediaIndex=0"; - params << "&partIndex=0"; - params << "&protocol=hls"; - params << "&offset=" << offset; - params << "&fastSeek=0"; - params << "&directPlay=0"; - params << "&directStream=1"; - params << "&subtitles=burn"; - //params << "&subtitleSize=90"; - //params << "&skipSubtitles=1"; - //params << "&audioBoost=100"; - - if(Config::GetInstance().UsePlexAccount) { - if(!pSrv->GetAuthToken().empty()) { - params << "&X-Plex-Token=" << pSrv->GetAuthToken(); - } - } + transcodeUri.addQueryParameter("path", pathUri.toString()); + transcodeUri.addQueryParameter("mediaIndex", "0"); + transcodeUri.addQueryParameter("partIndex", "0"); + transcodeUri.addQueryParameter("protocol", "hls"); + transcodeUri.addQueryParameter("offset", std::to_string(offset) ); + transcodeUri.addQueryParameter("fastSeek", "1"); + transcodeUri.addQueryParameter("directPlay", "0"); + transcodeUri.addQueryParameter("directStream", "1"); + transcodeUri.addQueryParameter("subtitles", "burn"); + transcodeUri.addQueryParameter("audioBoost", "100"); if(pSrv->IsLocal()) { - params << "&videoResolution=1920x1080"; - params << "&maxVideoBitrate=20000"; - params << "&videoQuality=100"; + transcodeUri.addQueryParameter("videoResolution", "1920x1080"); + transcodeUri.addQueryParameter("maxVideoBitrate", "20000"); + transcodeUri.addQueryParameter("videoQuality", "100"); } else { - params << "&videoResolution=1280x720"; - params << "&maxVideoBitrate=8000"; - params << "&videoQuality=100"; + transcodeUri.addQueryParameter("videoResolution", "1280x720"); + transcodeUri.addQueryParameter("maxVideoBitrate", "8000"); + transcodeUri.addQueryParameter("videoQuality", "100"); } - - params << "&session=" << encode(Config::GetInstance().GetUUID()); // TODO: generate Random SessionID - - params << "&includeCodecs=1"; - params << "©ts=1"; + transcodeUri.addQueryParameter("session", Config::GetInstance().GetUUID()); // TODO: generate Random SessionID + transcodeUri.addQueryParameter("includeCodecs", "1"); + transcodeUri.addQueryParameter("copyts", "1"); if(Config::GetInstance().UseAc3) { - params << "&X-Plex-Client-Profile-Extra="; - if(Config::GetInstance().UseAc3) - params << encode("add-transcode-target-audio-codec(type=videoProfile&context=streaming&protocol=hls&audioCodec=ac3)"); - + 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 pSrv->GetUri() + params.str(); + return transcodeUri.toString(); } } -- cgit v1.2.3