|
MythTV
0.26-pre
|
00001 // qt 00002 #include <QCoreApplication> 00003 #include <QImage> 00004 #include <QFileInfo> 00005 #include <QDir> 00006 #include <QEvent> 00007 00008 // myth 00009 #include "mythcorecontext.h" 00010 #include "mythuihelper.h" 00011 #include "mythdirs.h" 00012 #include "httpcomms.h" 00013 #include "storagegroup.h" 00014 #include "metadataimagedownload.h" 00015 #include "remotefile.h" 00016 #include "mythdownloadmanager.h" 00017 #include "mythlogging.h" 00018 00019 QEvent::Type ImageDLEvent::kEventType = 00020 (QEvent::Type) QEvent::registerEventType(); 00021 00022 QEvent::Type ImageDLFailureEvent::kEventType = 00023 (QEvent::Type) QEvent::registerEventType(); 00024 00025 QEvent::Type ThumbnailDLEvent::kEventType = 00026 (QEvent::Type) QEvent::registerEventType(); 00027 00028 MetadataImageDownload::MetadataImageDownload(QObject *parent) : 00029 MThread("MetadataImageDownload") 00030 { 00031 m_parent = parent; 00032 } 00033 00034 MetadataImageDownload::~MetadataImageDownload() 00035 { 00036 cancel(); 00037 wait(); 00038 } 00039 00040 void MetadataImageDownload::addThumb(QString title, 00041 QString url, QVariant data) 00042 { 00043 m_mutex.lock(); 00044 ThumbnailData *id = new ThumbnailData(); 00045 id->title = title; 00046 id->data = data; 00047 id->url = url; 00048 m_thumbnailList.append(id); 00049 if (!isRunning()) 00050 start(); 00051 m_mutex.unlock(); 00052 } 00053 00054 void MetadataImageDownload::addDownloads(MetadataLookup *lookup) 00055 { 00056 m_mutex.lock(); 00057 m_downloadList.append(lookup); 00058 if (!isRunning()) 00059 start(); 00060 m_mutex.unlock(); 00061 } 00062 00063 void MetadataImageDownload::cancel() 00064 { 00065 m_mutex.lock(); 00066 qDeleteAll(m_thumbnailList); 00067 m_thumbnailList.clear(); 00068 qDeleteAll(m_downloadList); 00069 m_downloadList.clear(); 00070 m_mutex.unlock(); 00071 } 00072 00073 void MetadataImageDownload::run() 00074 { 00075 RunProlog(); 00076 00077 // Always handle thumbnails first, they're higher priority. 00078 ThumbnailData *thumb; 00079 while ((thumb = moreThumbs()) != NULL) 00080 { 00081 QString sFilename = getDownloadFilename(thumb->title, thumb->url); 00082 00083 bool exists = QFile::exists(sFilename); 00084 if (!exists && !thumb->url.isEmpty()) 00085 GetMythDownloadManager()->download(thumb->url, sFilename); 00086 00087 // inform parent we have thumbnail ready for it 00088 if (QFile::exists(sFilename) && m_parent) 00089 { 00090 LOG(VB_GENERAL, LOG_DEBUG, 00091 QString("Threaded Image Thumbnail Download: %1") 00092 .arg(sFilename)); 00093 thumb->url = sFilename; 00094 QCoreApplication::postEvent(m_parent, 00095 new ThumbnailDLEvent(thumb)); 00096 } 00097 else 00098 delete thumb; 00099 } 00100 00101 MetadataLookup *lookup; 00102 while ((lookup = moreDownloads()) != NULL) 00103 { 00104 DownloadMap downloads = lookup->GetDownloads(); 00105 DownloadMap downloaded; 00106 00107 for (DownloadMap::iterator i = downloads.begin(); 00108 i != downloads.end(); ++i) 00109 { 00110 VideoArtworkType type = i.key(); 00111 ArtworkInfo info = i.value(); 00112 QString filename = getDownloadFilename( type, lookup, 00113 info.url ); 00114 if (lookup->GetHost().isEmpty()) 00115 { 00116 QString path = getLocalWritePath(lookup->GetType(), type); 00117 QDir dirPath(path); 00118 if (!dirPath.exists()) 00119 if (!dirPath.mkpath(path)) 00120 { 00121 LOG(VB_GENERAL, LOG_ERR, 00122 QString("Metadata Image Download: Unable to create " 00123 "path %1, aborting download.").arg(path)); 00124 QCoreApplication::postEvent(m_parent, 00125 new ImageDLFailureEvent(lookup)); 00126 continue; 00127 } 00128 QString finalfile = path + "/" + filename; 00129 QString oldurl = info.url; 00130 info.url = finalfile; 00131 if (!QFile::exists(finalfile) || lookup->GetAllowOverwrites()) 00132 { 00133 QFile dest_file(finalfile); 00134 if (dest_file.exists()) 00135 { 00136 QFileInfo fi(finalfile); 00137 GetMythUI()->RemoveFromCacheByFile(fi.fileName()); 00138 dest_file.remove(); 00139 } 00140 00141 LOG(VB_GENERAL, LOG_INFO, 00142 QString("Metadata Image Download: %1 ->%2") 00143 .arg(oldurl).arg(finalfile)); 00144 QByteArray *download = new QByteArray(); 00145 GetMythDownloadManager()->download(oldurl, download); 00146 00147 QImage testImage; 00148 bool didLoad = testImage.loadFromData(*download); 00149 if (!didLoad) 00150 { 00151 LOG(VB_GENERAL, LOG_ERR, 00152 QString("Tried to write %1, but it appears to be " 00153 "an HTML redirect (filesize %2).") 00154 .arg(oldurl).arg(download->size())); 00155 delete download; 00156 download = NULL; 00157 QCoreApplication::postEvent(m_parent, 00158 new ImageDLFailureEvent(lookup)); 00159 continue; 00160 } 00161 00162 if (dest_file.open(QIODevice::WriteOnly)) 00163 { 00164 off_t size = dest_file.write(*download, 00165 download->size()); 00166 if (size != download->size()) 00167 { 00168 LOG(VB_GENERAL, LOG_ERR, 00169 QString("Image Download: Error Writing Image " 00170 "to file: %1").arg(finalfile)); 00171 QCoreApplication::postEvent(m_parent, 00172 new ImageDLFailureEvent(lookup)); 00173 } 00174 else 00175 downloaded.insert(type, info); 00176 } 00177 00178 delete download; 00179 } 00180 else 00181 downloaded.insert(type, info); 00182 } 00183 else 00184 { 00185 QString path = getStorageGroupURL(type, lookup->GetHost()); 00186 QString finalfile = path + filename; 00187 QString oldurl = info.url; 00188 info.url = finalfile; 00189 bool exists = false; 00190 bool onMaster = false; 00191 QString resolvedFN; 00192 if ((lookup->GetHost().toLower() == gCoreContext->GetHostName().toLower()) || 00193 (gCoreContext->IsThisHost(lookup->GetHost()))) 00194 { 00195 StorageGroup sg; 00196 resolvedFN = sg.FindFile(filename); 00197 exists = QFile::exists(resolvedFN); 00198 if (!exists) 00199 { 00200 resolvedFN = getLocalStorageGroupPath(type, 00201 lookup->GetHost()) + "/" + filename; 00202 } 00203 onMaster = true; 00204 } 00205 else 00206 exists = RemoteFile::Exists(finalfile); 00207 00208 if (!exists || lookup->GetAllowOverwrites()) 00209 { 00210 00211 if (exists && !onMaster) 00212 { 00213 QFileInfo fi(finalfile); 00214 GetMythUI()->RemoveFromCacheByFile(fi.fileName()); 00215 RemoteFile::DeleteFile(finalfile); 00216 } 00217 else if (exists) 00218 QFile::remove(resolvedFN); 00219 00220 LOG(VB_GENERAL, LOG_INFO, 00221 QString("Metadata Image Download: %1 -> %2") 00222 .arg(oldurl).arg(finalfile)); 00223 QByteArray *download = new QByteArray(); 00224 GetMythDownloadManager()->download(oldurl, download); 00225 00226 QImage testImage; 00227 bool didLoad = testImage.loadFromData(*download); 00228 if (!didLoad) 00229 { 00230 LOG(VB_GENERAL, LOG_ERR, 00231 QString("Tried to write %1, but it appears to be " 00232 "an HTML redirect or corrupt file " 00233 "(filesize %2).") 00234 .arg(oldurl).arg(download->size())); 00235 delete download; 00236 download = NULL; 00237 QCoreApplication::postEvent(m_parent, 00238 new ImageDLFailureEvent(lookup)); 00239 continue; 00240 } 00241 00242 if (!onMaster) 00243 { 00244 RemoteFile *outFile = new RemoteFile(finalfile, true); 00245 if (!outFile->isOpen()) 00246 { 00247 LOG(VB_GENERAL, LOG_ERR, 00248 QString("Image Download: Failed to open " 00249 "remote file (%1) for write. Does " 00250 "Storage Group Exist?") 00251 .arg(finalfile)); 00252 delete outFile; 00253 outFile = NULL; 00254 QCoreApplication::postEvent(m_parent, 00255 new ImageDLFailureEvent(lookup)); 00256 } 00257 else 00258 { 00259 off_t written = outFile->Write(*download, 00260 download->size()); 00261 if (written != download->size()) 00262 { 00263 LOG(VB_GENERAL, LOG_ERR, 00264 QString("Image Download: Error Writing Image " 00265 "to file: %1").arg(finalfile)); 00266 QCoreApplication::postEvent(m_parent, 00267 new ImageDLFailureEvent(lookup)); 00268 } 00269 else 00270 downloaded.insert(type, info); 00271 delete outFile; 00272 outFile = NULL; 00273 } 00274 } 00275 else 00276 { 00277 QFile dest_file(resolvedFN); 00278 if (dest_file.open(QIODevice::WriteOnly)) 00279 { 00280 off_t size = dest_file.write(*download, 00281 download->size()); 00282 if (size != download->size()) 00283 { 00284 LOG(VB_GENERAL, LOG_ERR, 00285 QString("Image Download: Error Writing Image " 00286 "to file: %1").arg(finalfile)); 00287 QCoreApplication::postEvent(m_parent, 00288 new ImageDLFailureEvent(lookup)); 00289 } 00290 else 00291 downloaded.insert(type, info); 00292 } 00293 } 00294 00295 delete download; 00296 } 00297 else 00298 downloaded.insert(type, info); 00299 } 00300 } 00301 lookup->SetDownloads(downloaded); 00302 QCoreApplication::postEvent(m_parent, new ImageDLEvent(lookup)); 00303 } 00304 00305 RunEpilog(); 00306 } 00307 00308 ThumbnailData* MetadataImageDownload::moreThumbs() 00309 { 00310 ThumbnailData *ret = NULL; 00311 m_mutex.lock(); 00312 if (!m_thumbnailList.isEmpty()) 00313 ret = m_thumbnailList.takeFirst(); 00314 m_mutex.unlock(); 00315 return ret; 00316 } 00317 00318 MetadataLookup* MetadataImageDownload::moreDownloads() 00319 { 00320 MetadataLookup *ret = NULL; 00321 m_mutex.lock(); 00322 if (!m_downloadList.isEmpty()) 00323 ret = m_downloadList.takeFirst(); 00324 m_mutex.unlock(); 00325 return ret; 00326 } 00327 00328 QString getDownloadFilename(QString title, QString url) 00329 { 00330 QString fileprefix = GetConfDir(); 00331 00332 QDir dir(fileprefix); 00333 if (!dir.exists()) 00334 dir.mkdir(fileprefix); 00335 00336 fileprefix += "/thumbcache"; 00337 00338 dir = QDir(fileprefix); 00339 if (!dir.exists()) 00340 dir.mkdir(fileprefix); 00341 00342 QByteArray titlearr(title.toLatin1()); 00343 quint16 titleChecksum = qChecksum(titlearr.data(), titlearr.length()); 00344 QByteArray urlarr(url.toLatin1()); 00345 quint16 urlChecksum = qChecksum(urlarr.data(), urlarr.length()); 00346 QUrl qurl(url); 00347 QString ext = QFileInfo(qurl.path()).suffix(); 00348 QString basefilename = QString("thumbnail_%1_%2.%3") 00349 .arg(QString::number(urlChecksum)) 00350 .arg(QString::number(titleChecksum)).arg(ext); 00351 00352 QString outputfile = QString("%1/%2").arg(fileprefix).arg(basefilename); 00353 00354 return outputfile; 00355 } 00356 00357 QString getDownloadFilename(VideoArtworkType type, MetadataLookup *lookup, 00358 QString url) 00359 { 00360 QString basefilename; 00361 QString title; 00362 QString inter; 00363 uint tracknum = lookup->GetTrackNumber(); 00364 uint season = lookup->GetSeason(); 00365 uint episode = lookup->GetEpisode(); 00366 QString system = lookup->GetSystem(); 00367 if (season > 0 || episode > 0) 00368 { 00369 title = lookup->GetTitle(); 00370 if (title.contains("/")) 00371 title.replace("/", "-"); 00372 if (title.contains("?")) 00373 title.replace("?", ""); 00374 if (title.contains("*")) 00375 title.replace("*", ""); 00376 inter = QString(" Season %1").arg(QString::number(season)); 00377 if (type == kArtworkScreenshot) 00378 inter += QString("x%1").arg(QString::number(episode)); 00379 } 00380 else if (lookup->GetType() == kMetadataVideo || 00381 lookup->GetType() == kMetadataRecording) 00382 title = lookup->GetInetref(); 00383 else if (lookup->GetType() == kMetadataGame) 00384 title = QString("%1 (%2)").arg(lookup->GetTitle()) 00385 .arg(lookup->GetSystem()); 00386 00387 if (tracknum > 0) 00388 inter = QString(" Track %1").arg(QString::number(tracknum)); 00389 else if (!system.isEmpty()) 00390 inter = QString(" (%1)").arg(system); 00391 00392 QString suffix; 00393 QUrl qurl(url); 00394 QString ext = QFileInfo(qurl.path()).suffix(); 00395 00396 if (type == kArtworkCoverart) 00397 suffix = "_coverart"; 00398 else if (type == kArtworkFanart) 00399 suffix = "_fanart"; 00400 else if (type == kArtworkBanner) 00401 suffix = "_banner"; 00402 else if (type == kArtworkScreenshot) 00403 suffix = "_screenshot"; 00404 else if (type == kArtworkPoster) 00405 suffix = "_poster"; 00406 else if (type == kArtworkBackCover) 00407 suffix = "_backcover"; 00408 else if (type == kArtworkInsideCover) 00409 suffix = "_insidecover"; 00410 else if (type == kArtworkCDImage) 00411 suffix = "_cdimage"; 00412 00413 basefilename = title + inter + suffix + "." + ext; 00414 00415 return basefilename; 00416 } 00417 00418 QString getLocalWritePath(MetadataType metadatatype, VideoArtworkType type) 00419 { 00420 QString ret; 00421 00422 if (metadatatype == kMetadataVideo) 00423 { 00424 if (type == kArtworkCoverart) 00425 ret = gCoreContext->GetSetting("VideoArtworkDir"); 00426 else if (type == kArtworkFanart) 00427 ret = gCoreContext->GetSetting("mythvideo.fanartDir"); 00428 else if (type == kArtworkBanner) 00429 ret = gCoreContext->GetSetting("mythvideo.bannerDir"); 00430 else if (type == kArtworkScreenshot) 00431 ret = gCoreContext->GetSetting("mythvideo.screenshotDir"); 00432 } 00433 else if (metadatatype == kMetadataMusic) 00434 { 00435 } 00436 else if (metadatatype == kMetadataGame) 00437 { 00438 if (type == kArtworkCoverart) 00439 ret = gCoreContext->GetSetting("mythgame.boxartdir"); 00440 else if (type == kArtworkFanart) 00441 ret = gCoreContext->GetSetting("mythgame.fanartdir"); 00442 else if (type == kArtworkScreenshot) 00443 ret = gCoreContext->GetSetting("mythgame.screenshotdir"); 00444 } 00445 00446 return ret; 00447 } 00448 00449 QString getStorageGroupURL(VideoArtworkType type, QString host) 00450 { 00451 QString sgroup; 00452 QString ip = gCoreContext->GetSettingOnHost("BackendServerIP", host); 00453 uint port = gCoreContext->GetSettingOnHost("BackendServerPort", 00454 host).toUInt(); 00455 00456 if (type == kArtworkCoverart) 00457 sgroup = "Coverart"; 00458 else if (type == kArtworkFanart) 00459 sgroup = "Fanart"; 00460 else if (type == kArtworkBanner) 00461 sgroup = "Banners"; 00462 else if (type == kArtworkScreenshot) 00463 sgroup = "Screenshots"; 00464 else 00465 sgroup = "Default"; 00466 00467 return gCoreContext->GenMythURL(ip,port,"",sgroup); 00468 } 00469 00470 QString getLocalStorageGroupPath(VideoArtworkType type, QString host) 00471 { 00472 QString path; 00473 00474 StorageGroup sg; 00475 00476 if (type == kArtworkCoverart) 00477 sg.Init("Coverart", host); 00478 else if (type == kArtworkFanart) 00479 sg.Init("Fanart", host); 00480 else if (type == kArtworkBanner) 00481 sg.Init("Banners", host); 00482 else if (type == kArtworkScreenshot) 00483 sg.Init("Screenshots", host); 00484 else 00485 sg.Init("Default", host); 00486 00487 path = sg.FindNextDirMostFree(); 00488 00489 return path; 00490 } 00491 00492 void cleanThumbnailCacheDir() 00493 { 00494 QString cache = QString("%1/thumbcache") 00495 .arg(GetConfDir()); 00496 QDir cacheDir(cache); 00497 QStringList thumbs = cacheDir.entryList(QDir::Files); 00498 00499 for (QStringList::const_iterator i = thumbs.end() - 1; 00500 i != thumbs.begin() - 1; --i) 00501 { 00502 QString filename = QString("%1/%2").arg(cache).arg(*i); 00503 QFileInfo fi(filename); 00504 QDateTime lastmod = fi.lastModified(); 00505 if (lastmod.addDays(2) < QDateTime::currentDateTime()) 00506 { 00507 LOG(VB_GENERAL, LOG_DEBUG, QString("Deleting file %1") 00508 .arg(filename)); 00509 QFile::remove(filename); 00510 } 00511 } 00512 } 00513
1.7.6.1