summaryrefslogtreecommitdiff
path: root/Plexservice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Plexservice.cpp')
-rw-r--r--Plexservice.cpp597
1 files changed, 297 insertions, 300 deletions
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();
+ }
}