diff options
author | chriszero <zerov83@gmail.com> | 2015-02-05 21:32:55 +0100 |
---|---|---|
committer | chriszero <zerov83@gmail.com> | 2015-02-05 21:32:55 +0100 |
commit | 312c13f4f6b299a976787542869f96b1e66549cf (patch) | |
tree | 7ee2732eaec79d50e0c9718960fd58e2436f10f6 /PlexHTTPRequestHandler.cpp | |
parent | 1ecdb2a5d9e05e0d30dae89e3d675218ca4c255e (diff) | |
download | vdr-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.cpp | 298 |
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; } - + } } |