#include "PlexHTTPRequestHandler.h" #include #include #include #include "hlsPlayerControl.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", "player"); response.add("X-Plex-Product", "PlexVDR"); 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 PlexHTTPRequestHandler::ParseQuery(std::string query) { std::map querymap; Poco::StringTokenizer queryTokens(query, "&"); for(Poco::StringTokenizer::Iterator token = queryTokens.begin() ; token != queryTokens.end(); ++token) { Poco::StringTokenizer subTokens(*token, "="); querymap[subTokens[0]] = subTokens[1]; } return querymap; } std::string PlexHTTPRequestHandler::GetOKMsg() { return " "; } void PlexHTTPRequestHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) { UpdateCommandId(request); AddHeaders(response, request); response.send() << GetOKMsg(); } void PlexHTTPRequestHandler::UpdateCommandId(Poco::Net::HTTPServerRequest& request) { Poco::URI uri(request.getURI()); std::map 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 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 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 << "" "" " "; 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 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("/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(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; } } }