svvitch
digital signage player
|
00001 #include <Poco/AutoPtr.h> 00002 #include <Poco/DOM/DOMParser.h> 00003 #include <Poco/DOM/Document.h> 00004 #include <Poco/DOM/Element.h> 00005 #include <Poco/DOM/NodeList.h> 00006 #include <Poco/DOM/DOMWriter.h> 00007 #include <Poco/XML/XMLWriter.h> 00008 #include <Poco/DateTime.h> 00009 #include <Poco/DateTimeFormat.h> 00010 #include <Poco/DateTimeParser.h> 00011 #include <Poco/Timezone.h> 00012 #include <Poco/Exception.h> 00013 #include <Poco/FileStream.h> 00014 #include <Poco/format.h> 00015 #include <Poco/hash.h> 00016 #include <Poco/string.h> 00017 #include <Poco/UnicodeConverter.h> 00018 00019 #include "Workspace.h" 00020 #include "Utils.h" 00021 00022 using Poco::XML::Document; 00023 using Poco::XML::Element; 00024 using Poco::XML::NodeList; 00025 00026 00027 Workspace::Workspace(Path file): _log(Poco::Logger::get("")), _file(file) { 00028 } 00029 00030 Workspace::‾Workspace() { 00031 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00032 release(); 00033 } 00034 00035 00036 void Workspace::release() { 00037 for (vector<SchedulePtr>::iterator it = _schedule.begin(); it != _schedule.end(); it++) { 00038 SAFE_DELETE(*it); 00039 } 00040 for (vector<PlayListPtr>::iterator it = _playlist.begin(); it != _playlist.end(); it++) { 00041 PlayListPtr playlist = *it; 00042 // _renderer.removeCachedTexture(playlist->name()); 00043 SAFE_DELETE(playlist); 00044 } 00045 _playlistMap.clear(); 00046 _playlist.clear(); 00047 00048 for (vector<MediaItemPtr>::iterator it = _media.begin(); it != _media.end(); it++) { 00049 MediaItemPtr media = *it; 00050 // _renderer.removeCachedTexture(media->id()); 00051 SAFE_DELETE(media); 00052 } 00053 _mediaMap.clear(); 00054 _media.clear(); 00055 _log.information("release workspace"); 00056 } 00057 00058 const Path& Workspace::file() const { 00059 return _file; 00060 } 00061 00062 bool Workspace::checkUpdate() { 00063 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00064 string signature = svvitch::md5(_file.toString()); 00065 if (_signature != signature) { 00066 _log.information(Poco::format("detect update workspace: %s", _signature)); 00067 return true; 00068 } 00069 return false; 00070 } 00071 00072 bool Workspace::parse() { 00073 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00074 try { 00075 string signature = svvitch::md5(_file); 00076 Poco::XML::DOMParser parser; 00077 Document* doc = parser.parse(_file.toString()); 00078 if (doc) { 00079 _log.information(Poco::format("update/parse workspace file: %s", _file.toString())); 00080 release(); 00081 NodeList* nodes = doc->documentElement()->getElementsByTagName("medialist"); 00082 if (nodes) { 00083 _media.clear(); 00084 _existsFiles.clear(); 00085 for (int i = 0; i < nodes->length(); i++) { 00086 Element* e = (Element*)nodes->item(i); 00087 NodeList* items = e->getElementsByTagName("item"); 00088 for (int j = 0; j < items->length(); j++) { 00089 e = (Element*)items->item(j); 00090 string type = Poco::toLower(e->getAttribute("type")); 00091 string name = e->getAttribute("name"); 00092 string id = e->getAttribute("id"); 00093 string s = e->getAttribute("start"); 00094 int start = 0; 00095 if (!s.empty()) { 00096 start = Poco::NumberParser::parse(s); 00097 } 00098 string d = e->getAttribute("duration"); 00099 int duration = 0; 00100 if (!d.empty()) { 00101 duration = Poco::NumberParser::parse(d); 00102 } 00103 string parameters = e->getAttribute("params"); 00104 vector<MediaItemFile> files; 00105 NodeList* movies = e->getElementsByTagName("*"); 00106 for (int k = 0; k < movies->length(); k++) { 00107 e = (Element*)movies->item(k); 00108 string file = e->innerText(); 00109 if (file.find("switch-data:/") == 0) { 00110 file = Path(config().dataRoot, file.substr(13)).toString(); 00111 } 00112 string params; 00113 if (file.find("?") != string::npos) { 00114 params = file.substr(file.find("?") + 1); 00115 file = file.substr(0, file.find("?")); 00116 } 00117 if (e->tagName() == "movie") { 00118 files.push_back(MediaItemFile(MediaTypeMovie, file, params)); 00119 } else if (e->tagName() == "image") { 00120 files.push_back(MediaItemFile(MediaTypeImage, file, params)); 00121 } else if (e->tagName() == "text") { 00122 files.push_back(MediaItemFile(MediaTypeText, file, params)); 00123 } else if (e->tagName() == "flash") { 00124 files.push_back(MediaItemFile(MediaTypeFlash, file, params)); 00125 } else { 00126 files.push_back(MediaItemFile(MediaTypeUnknown, file, params)); 00127 } 00128 } 00129 movies->release(); 00130 00131 MediaType typeCode = MediaTypeUnknown; 00132 if (type == "mix") { 00133 typeCode = MediaTypeMix; 00134 } else if (type == "movie") { 00135 typeCode = MediaTypeMovie; 00136 } else if (type == "image") { 00137 typeCode = MediaTypeImage; 00138 } else if (type == "flash") { 00139 typeCode = MediaTypeFlash; 00140 } else if (type == "browser") { 00141 typeCode = MediaTypeBrowser; 00142 } else if (type == "cv") { 00143 typeCode = MediaTypeCv; 00144 } else if (type == "cvcap") { 00145 typeCode = MediaTypeCvCap; 00146 } else if (type == "game") { 00147 typeCode = MediaTypeGame; 00148 } else if (type == "game2") { 00149 typeCode = MediaTypeGame2; 00150 } 00151 Poco::HashMap<string, MediaItemPtr>::Iterator find = _mediaMap.find(id); 00152 if (find != _mediaMap.end()) { 00153 _log.warning(Poco::format("already registed media, delete old item: %s", id)); 00154 for (vector<MediaItemPtr>::iterator it = _media.begin(); it != _media.end(); it++) { 00155 MediaItemPtr media = *it; 00156 if (id == media->id()) { 00157 _media.erase(it); 00158 break; 00159 } 00160 } 00161 SAFE_DELETE(find->second); 00162 _mediaMap.erase(find); 00163 } 00164 MediaItemPtr media = new MediaItem(typeCode, id, name, start, duration, parameters, files); 00165 _mediaMap[id] = media; 00166 _media.push_back(media); 00167 switch (media->type()) { 00168 case MediaTypeMix: 00169 case MediaTypeMovie: 00170 case MediaTypeImage: 00171 case MediaTypeText: 00172 case MediaTypeFlash: 00173 for (vector<MediaItemFile>::const_iterator it = files.begin(); it != files.end(); it++) { 00174 if (!((*it).file().empty()) && (*it).file().find("http") == string::npos) { 00175 try { 00176 File f = File((*it).file()); 00177 if (f.exists()) _existsFiles.push_back(f.path()); 00178 } catch (Poco::FileException& ex) { 00179 } 00180 } 00181 } 00182 } 00183 } 00184 items->release(); 00185 } 00186 nodes->release(); 00187 } 00188 _log.information(Poco::format("media item: %?u", _media.size())); 00189 00190 nodes = doc->documentElement()->getElementsByTagName("playlists"); 00191 if (nodes) { 00192 for (int i = 0; i < nodes->length(); i++) { 00193 Element* e = (Element*)nodes->item(i); 00194 NodeList* nodesPlaylist = e->getElementsByTagName("playlist"); 00195 for (int j = 0; j < nodesPlaylist->length(); j++) { 00196 e = (Element*)nodesPlaylist->item(j); 00197 string name = e->getAttribute("name"); 00198 string id = e->getAttribute("id"); 00199 if (id.empty()) { 00200 // TODO playlist.id指定が無い時の処理 00201 id = Poco::format("g%04d", j); 00202 // _log.information(Poco::format("auto group id: %s", id)); 00203 } 00204 string text = e->getAttribute("text"); 00205 PlayListPtr playlist = new PlayList(id, name, text); 00206 NodeList* items = e->getElementsByTagName("item"); 00207 for (int k = 0; k < items->length(); k++) { 00208 e = (Element*)items->item(k); 00209 string id = e->innerText(); 00210 string next = e->getAttribute("next"); 00211 string transition = e->getAttribute("transition"); 00212 Poco::HashMap<string, MediaItemPtr>::Iterator it = _mediaMap.find(id); 00213 if (it != _mediaMap.end()) { 00214 playlist->add(new PlayListItem(it->second, next, transition)); 00215 } else { 00216 _log.warning(Poco::format("not found item[id:%s] in playlist[name:%s]", id, name)); 00217 } 00218 } 00219 _playlistMap[id] = playlist; 00220 _playlist.push_back(playlist); 00221 // _log.debug(Poco::format("playlist: %s x%d", playlist->name(), playlist->itemCount())); 00222 items->release(); 00223 } 00224 nodesPlaylist->release(); 00225 } 00226 nodes->release(); 00227 } 00228 _log.information(Poco::format("playlist: %?u", _playlist.size())); 00229 00230 nodes = doc->documentElement()->getElementsByTagName("schedule"); 00231 if (nodes) { 00232 for (int i = 0; i < nodes->length(); i++) { 00233 Element* schedule = (Element*)nodes->item(i); 00234 NodeList* items = schedule->getElementsByTagName("item"); 00235 for (int j = 0; j < items->length(); j++) { 00236 Element* e = (Element*)items->item(j); 00237 string id = e->getAttribute("id"); 00238 string t = e->getAttribute("time"); 00239 string command = e->innerText(); 00240 vector<int> time = svvitch::parseTimes(t); 00241 if (time.size() == 7) { 00242 SchedulePtr schedule = new Schedule(id, time[0], time[1], time[2], time[3], time[4], time[5], time[6], command); 00243 _schedule.push_back(schedule); 00244 } else if (time.size() == 6) { 00245 // spec of old 00246 SchedulePtr schedule = new Schedule(id, time[0], time[1], time[2], time[3], time[4], 0, time[5], command); 00247 _schedule.push_back(schedule); 00248 } 00249 } 00250 items->release(); 00251 } 00252 nodes->release(); 00253 } 00254 00255 nodes = doc->documentElement()->getElementsByTagName("fonts"); 00256 if (nodes) { 00257 for (int i = 0; i < nodes->length(); i++) { 00258 Element* fonts = (Element*)nodes->item(i); 00259 NodeList* files = fonts->getElementsByTagName("file"); 00260 for (int j = 0; j < files->length(); j++) { 00261 Element* e = (Element*)files->item(j); 00262 string path = e->innerText(); 00263 if (path.find("switch-data:/") == 0) { 00264 Path p(config().dataRoot, path.substr(13)); 00265 path = p.parse(p.toString()).toString(); 00266 } 00267 _fonts.push_back(path); 00268 } 00269 } 00270 } 00271 doc->release(); 00272 _signature = signature; 00273 return true; 00274 } else { 00275 _log.warning(Poco::format("failed parse: %s", _file)); 00276 } 00277 } catch (Poco::Exception& ex) { 00278 _log.warning(ex.displayText()); 00279 } 00280 return false; 00281 } 00282 00283 const int Workspace::getMediaCount() { 00284 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00285 return _media.size(); 00286 } 00287 00288 const MediaItemPtr Workspace::getMedia(int i) { 00289 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00290 if (i >= 0 && i < _media.size()) { 00291 return _media[i]; 00292 } 00293 return NULL; 00294 } 00295 00296 const MediaItemPtr Workspace::getMedia(string id) { 00297 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00298 Poco::HashMap<string, MediaItemPtr>::Iterator it = _mediaMap.find(id); 00299 if (it != _mediaMap.end()) { 00300 return it->second; 00301 } 00302 return NULL; 00303 } 00304 00305 00306 const int Workspace::getPlaylistCount() { 00307 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00308 return _playlist.size(); 00309 } 00310 00311 const PlayListPtr Workspace::getPlaylist(int i) { 00312 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00313 if (i >= 0 && i < _playlist.size()) { 00314 return _playlist[i]; 00315 } 00316 return NULL; 00317 } 00318 00319 const PlayListPtr Workspace::getPlaylist(string id) { 00320 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00321 Poco::HashMap<string, PlayListPtr>::Iterator it = _playlistMap.find(id); 00322 if (it != _playlistMap.end()) { 00323 return it->second; 00324 } 00325 return NULL; 00326 } 00327 00328 const vector<string> Workspace::getFonts() { 00329 return _fonts; 00330 } 00331 00332 const int Workspace::getScheduleCount() { 00333 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00334 return _schedule.size(); 00335 } 00336 00337 const SchedulePtr Workspace::getSchedule(int i) { 00338 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00339 if (i >= 0 && i < _schedule.size()) { 00340 return _schedule[i]; 00341 } 00342 return NULL; 00343 } 00344 00345 const vector<string> Workspace::existsFiles() { 00346 Poco::ScopedLock<Poco::FastMutex> lock(_lock); 00347 return _existsFiles; 00348 } 00349 00350 const string Workspace::signature() const { 00351 return _signature; 00352 }