summaryrefslogtreecommitdiff
path: root/PlexHTTPRequestHandler.cpp
diff options
context:
space:
mode:
authorchriszero <zerov83@gmail.com>2015-02-05 21:32:55 +0100
committerchriszero <zerov83@gmail.com>2015-02-05 21:32:55 +0100
commit312c13f4f6b299a976787542869f96b1e66549cf (patch)
tree7ee2732eaec79d50e0c9718960fd58e2436f10f6 /PlexHTTPRequestHandler.cpp
parent1ecdb2a5d9e05e0d30dae89e3d675218ca4c255e (diff)
downloadvdr-plugin-plex-312c13f4f6b299a976787542869f96b1e66549cf.tar.gz
vdr-plugin-plex-312c13f4f6b299a976787542869f96b1e66549cf.tar.bz2
Plex remote support.
Control via Plexapps (Android, IOS...)
Diffstat (limited to 'PlexHTTPRequestHandler.cpp')
-rw-r--r--PlexHTTPRequestHandler.cpp298
1 files changed, 189 insertions, 109 deletions
diff --git a/PlexHTTPRequestHandler.cpp b/PlexHTTPRequestHandler.cpp
index d6c8ad3..7ba12f1 100644
--- a/PlexHTTPRequestHandler.cpp
+++ b/PlexHTTPRequestHandler.cpp
@@ -3,12 +3,15 @@
#include <vdr/keys.h>
#include <unistd.h>
+#include "hlsPlayerControl.h"
+
namespace plexclient
{
-void PlexHTTPRequestHandler::AddHeaders(Poco::Net::HTTPServerResponse& response, Poco::Net::HTTPServerRequest& request) {
+void PlexHTTPRequestHandler::AddHeaders(Poco::Net::HTTPServerResponse& response, Poco::Net::HTTPServerRequest& request)
+{
if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) {
- response.setContentType("text/plain");
+ response.setContentType("text/plain");
response.add("X-Plex-Client-Identifier", Config::GetInstance().GetUUID());
response.add("Connection", "Close");
@@ -16,12 +19,12 @@ void PlexHTTPRequestHandler::AddHeaders(Poco::Net::HTTPServerResponse& response,
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");
+ "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.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());
@@ -36,7 +39,8 @@ void PlexHTTPRequestHandler::AddHeaders(Poco::Net::HTTPServerResponse& response,
//header.MessageHeader(header);
}
-std::map<std::string, std::string> PlexHTTPRequestHandler::ParseQuery(std::string query) {
+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) {
@@ -46,137 +50,213 @@ std::map<std::string, std::string> PlexHTTPRequestHandler::ParseQuery(std::strin
return querymap;
}
-std::string PlexHTTPRequestHandler::GetOKMsg() {
+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){
+void PlexHTTPRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
+{
+ UpdateCommandId(request);
+
AddHeaders(response, request);
- std::ostream& ostr = response.send();
- ostr << GetOKMsg();
+ response.send() << GetOKMsg();
}
-void SubscribeRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response){
- // parse query
+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 path = uri.getPath(); // /player/timeline/subscribe
-
- std::string uuid = request.get("X-Plex-Client-Identifier");
- int port = atoi(query["port"].c_str());
- int command = atoi(query["commandID"].c_str());
- SubscriptionManager::GetInstance().AddSubscriber(Subscriber(query["protocol"], request.getHost(), port, uuid, command));
-
- AddHeaders(response, request);
-
- std::ostream& ostr = response.send();
- ostr << GetOKMsg();
- response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK);
-}
-
-void ResourceRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response){
- 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=\"PlexVDR\""
- " platform=\"Linux\""
- " platformVersion=\"" << VERSION << "\""
- " deviceClass=\"HTPC\""
- "/> </MediaContainer>";
-
- response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK);
- dsyslog("[plex]Resources Response sent...");
+ std::string uuid = request.get("X-Plex-Client-Identifier", "");
+ if (uuid.length() != 0) {
+ std::string command = query["commandID"];
+ SubscriptionManager::GetInstance().UpdateSubscriber(uuid, command);
+ }
}
-void PlayerRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response){
+void SubscribeRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
+{
+ UpdateCommandId(request);
Poco::URI uri(request.getURI());
- //Poco::StringTokenizer pathTokens(uri, "/");
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.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK);
- std::ostream& ostr = response.send(); // Stream must not be empty!
- ostr << " ";
+ response.send() << " "; // Stream must not be empty!
response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK);
- dsyslog("[plex]OPTION Reply send");
return;
- }
-
- if(request.getURI().find("/poll")!= std::string::npos) {
+ }
+
+ // 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");
-
- std::ostream& ostr = response.send();
- ostr << SubscriptionManager::GetInstance().GetMsg(query["commandID"]);
- response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK);
-
- }
- else if(request.getURI().find("/playback/playMedia")!= std::string::npos) {
- //std::cout << "playMedia_1" << std::endl;
- AddHeaders(response, request);
-
- //std::cout << "playMedia_2" << std::endl;
- std::string protocol = query["protocol"];
- std::string address = query["address"];
- std::string port = query["port"];
- std::string key = query["key"];
- //std::cout << "playMedia_3" << std::endl;
-
- std::string fullUrl = protocol + "://" + address + ":" + port + key; // Metainfo
- std::cout << "FullUrl: " << fullUrl << std::endl;
-
- MediaContainer *pCont = Plexservice::GetMediaContainer(fullUrl);
- std::string filePath = pCont->m_vVideos[0].m_Media.m_sPartKey;
- Poco::URI fileuri(fullUrl);
- fileuri.setPath(filePath);
-
- // MUSS im Maintread des Plugins/VDR gestartet werden
- ActionManager::GetInstance().AddAction(fileuri.toString());
-
- std::ostream& ostr = response.send();
- ostr << GetOKMsg();
+ response.send() << SubscriptionManager::GetInstance().GetMsg(query["commandID"]);
response.setStatus(Poco::Net::HTTPResponse::HTTP_REASON_OK);
- SubscriptionManager::GetInstance().Notify();
}
- 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);
+}
+
+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=\"PlexVDR\""
+ " 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);
}
- else if(request.getURI().find("/home")!= std::string::npos) {
- cRemote::Put(kMenu);
+
+ if(request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) {
+ AddHeaders(response, request);
+ response.send() << " "; // Stream must not be empty!
+ return;
}
- else if(request.getURI().find("/back")!= std::string::npos) {
- cRemote::Put(kBack);
+
+ 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("/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
+
+ MediaContainer *pCont = Plexservice::GetMediaContainer(fullUrl);
+
+ // MUSS im Maintread des Plugins/VDR gestartet werden
+ if(query.find("offset") != query.end()) {
+ pCont->m_vVideos[0].m_iMyPlayOffset = atoi(query["offset"].c_str()) / 1000;
+ }
+ ActionManager::GetInstance().AddAction(&pCont->m_vVideos[0]); // MemoryLeak?
+
+ response.send() << GetOKMsg();
+
+ SubscriptionManager::GetInstance().Notify();
+
+ } 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("/seekTo")!= std::string::npos) {
+ if(query.find("offset") != query.end()) {
+ int offset = atoi(query["offset"].c_str()) / 1000;
+ cHlsPlayerControl* control = dynamic_cast<cHlsPlayerControl*>(cControl::Control(true));
+ if(control) {
+ isyslog("[plex] Seeking to %d", offset);
+ control->SeekTo(offset);
+ }
+ }
+ } else if(request.getURI().find("/play")!= std::string::npos) {
+ cRemote::Put(kPlay);
+ } else if(request.getURI().find("/pause")!= std::string::npos) {
+ cRemote::Put(kPause);
+ } else if(request.getURI().find("/stop")!= std::string::npos) {
+ cRemote::Put(kStop);
+ } else if(request.getURI().find("/stepForward")!= std::string::npos) {
+ cRemote::Put(kFastFwd);
+ } else if(request.getURI().find("/stepBack")!= std::string::npos) {
+ cRemote::Put(kFastRew);
+ } else if(request.getURI().find("/skipNext")!= std::string::npos) {
+ cRemote::Put(kFastFwd);
+ } else if(request.getURI().find("/skipPrevious")!= std::string::npos) {
+ cRemote::Put(kFastRew);
+ }
+ SubscriptionManager::GetInstance().Notify();
+ response.send() << GetOKMsg();
}
+ } catch (Poco::Exception& e) {
+ std::cerr << e.displayText() << std::endl;
}
-
+
}
}