/** \fn DBUtil::CheckRepairStatus(MSqlQuery &query) * \brief Parse the results of a CHECK TABLE or REPAIR TABLE run. * * This function reads the records returned by a CHECK TABLE or REPAIR TABLE * run and determines the status of the table(s). The query should have * columns Table, Msg_type, and Msg_text. * * The function properly handles multiple records for a single table. If the * last record for a given table shows a status (Msg_type) of OK (Msg_text), * the table is considered OK, even if an error or warning appeared before * (this could be the case, for example, when an empty table is crashed). * * \param query An already-executed CHECK TABLE or REPAIR TABLE query whose * results should be parsed. * \return A list of names of not-OK (errored or crashed) tables * \sa DBUtil::CheckTables(const bool, const QString) * \sa DBUtil::RepairTables(const QStringList) */ QStringList DBUtil::CheckRepairStatus(MSqlQuery &query) { QStringList tables; QSqlRecord record = query.record(); int table_index = record.indexOf("Table"); int type_index = record.indexOf("Msg_type"); int text_index = record.indexOf("Msg_text"); QString table, type, text, previous_table; bool ok = true; while (query.next()) { table = query.value(table_index).toString(); type = query.value(type_index).toString(); text = query.value(text_index).toString(); if (table != previous_table) { if (!ok) { tables.append(previous_table); ok = true; } previous_table = table; } // If the final row shows status OK, the table is now good if ("status" == type.toLower() && "ok" == text.toLower()) ok = true; else if ("error" == type.toLower() || ("status" == type.toLower() && "ok" != text.toLower())) ok = false; } // Check the last table in the list if (!ok) tables.append(table); return tables; }
static void fill_settings( MythSettingList &settings, MSqlQuery &query, MythSetting::SettingType stype) { QMap<QString,QString> map; while (query.next()) map[query.value(0).toString()] = query.value(1).toString(); MythSettingList::const_iterator it = settings.begin(); for (; it != settings.end(); ++it) fill_setting(*it, map, stype); }
/** \fn ImageUtils::LoadDirectoryValues(MSqlQuery &, ImageMetadata *) * \brief Loads the directory information from the database into the dataMap * \param query Information from the database * \param dm Holds the loaded information * \return void */ void ImageUtils::LoadDirectoryValues(MSqlQuery &query, ImageMetadata *dm) { dm->m_id = query.value(0).toInt(); dm->m_fileName = query.value(1).toString(); dm->m_name = query.value(2).toString(); dm->m_path = query.value(3).toString(); dm->m_parentId = query.value(4).toInt(); dm->m_dirCount = query.value(5).toInt(); dm->m_fileCount = query.value(6).toInt(); dm->m_isHidden = query.value(7).toInt(); // preset all directories as subfolders dm->m_type = kSubDirectory; }
/** \fn GalleryDatabaseHelper::LoadDirectoryValues(MSqlQuery &, ImageMetadata *) * \brief Loads the directory information from the database * \param query Information from the database * \param im Holds the loaded information * \return void */ void GalleryDatabaseHelper::LoadDirectoryValues(MSqlQuery &query, ImageMetadata *im) { im->m_id = query.value(0).toInt(); im->m_fileName = query.value(1).toString(); im->m_name = query.value(2).toString(); im->m_path = query.value(3).toString(); im->m_parentId = query.value(4).toInt(); im->m_dirCount = query.value(5).toInt(); im->m_fileCount = query.value(6).toInt(); im->m_isHidden = query.value(7).toInt(); // preset all directories as subfolders im->m_type = kSubDirectory; LoadDirectoryThumbnailValues(im); }
bool ProgramData::DeleteOverlaps( MSqlQuery &query, uint chanid, const ProgInfo &pi) { if (VERBOSE_LEVEL_CHECK(VB_XMLTV, LOG_INFO)) { // Get overlaps.. query.prepare( "SELECT title,starttime,endtime " "FROM program " "WHERE chanid = :CHANID AND " " starttime >= :START AND " " starttime < :END;"); query.bindValue(":CHANID", chanid); query.bindValue(":START", pi.starttime); query.bindValue(":END", pi.endtime); if (!query.exec()) return false; if (!query.next()) return true; do { LOG(VB_XMLTV, LOG_INFO, QString("Removing existing program: %1 - %2 %3 %4") .arg(query.value(1).toDateTime().toString(Qt::ISODate)) .arg(query.value(2).toDateTime().toString(Qt::ISODate)) .arg(pi.channel) .arg(query.value(0).toString())); } while (query.next()); } if (!ClearDataByChannel(chanid, pi.starttime, pi.endtime, false)) { LOG(VB_XMLTV, LOG_ERR, QString("Program delete failed : %1 - %2 %3 %4") .arg(pi.starttime.toString(Qt::ISODate)) .arg(pi.endtime.toString(Qt::ISODate)) .arg(pi.channel) .arg(pi.title)); return false; } return true; }
/** \fn ImageUtils::LoadFileValues(MSqlQuery &, ImageMetadata *) * \brief Loads the file information from the database into the dataMap * \param query Information from the database * \param dm Holds the loaded information * \return void */ void ImageUtils::LoadFileValues(MSqlQuery &query, ImageMetadata *dm) { dm->m_id = query.value(0).toInt(); dm->m_fileName = query.value(1).toString(); dm->m_name = query.value(2).toString(); dm->m_path = query.value(3).toString(); dm->m_parentId = query.value(4).toInt(); dm->m_type = query.value(5).toInt(); dm->m_modTime = query.value(6).toInt(); dm->m_size = query.value(7).toInt(); dm->m_extension = query.value(8).toString(); dm->SetAngle( query.value(9).toInt()); dm->m_date = query.value(10).toInt(); dm->SetZoom( query.value(11).toInt()); dm->m_isHidden = query.value(12).toInt(); dm->SetOrientation( query.value(13).toInt(), true); }
/** \fn GalleryDatabaseHelper::LoadFileValues(MSqlQuery &, ImageMetadata *) * \brief Loads the file information from the database * \param query Information from the database * \param im Holds the loaded information * \return void */ void GalleryDatabaseHelper::LoadFileValues(MSqlQuery &query, ImageMetadata *im) { im->m_id = query.value(0).toInt(); im->m_fileName = query.value(1).toString(); im->m_name = query.value(2).toString(); im->m_path = query.value(3).toString(); im->m_parentId = query.value(4).toInt(); im->m_type = query.value(5).toInt(); im->m_modTime = query.value(6).toInt(); im->m_size = query.value(7).toInt(); im->m_extension = query.value(8).toString(); im->SetAngle( query.value(9).toInt()); im->m_date = query.value(10).toInt(); im->SetZoom( query.value(11).toInt()); im->m_isHidden = query.value(12).toInt(); im->SetOrientation( query.value(13).toInt(), true); LoadFileThumbnailValues(im); }
uint DBPerson::GetPersonDB(MSqlQuery &query) const { query.prepare( "SELECT person " "FROM people " "WHERE name = :NAME"); query.bindValue(":NAME", name); if (!query.exec()) MythDB::DBError("get_person", query); else if (query.next()) return query.value(0).toUInt(); return 0; }
void UPnpCDSTv::AddItem( const UPnpCDSRequest *pRequest, const QString &sObjectId, UPnpCDSExtensionResults *pResults, bool bAddRef, MSqlQuery &query ) { int nChanid = query.value( 0).toInt(); QDateTime dtStartTime = query.value( 1).toDateTime(); QDateTime dtEndTime = query.value( 2).toDateTime(); QString sTitle = query.value( 3).toString(); QString sSubtitle = query.value( 4).toString(); QString sDescription = query.value( 5).toString(); QString sCategory = query.value( 6).toString(); QString sHostName = query.value( 7).toString(); QString sRecGroup = query.value( 8).toString(); uint64_t nFileSize = query.value( 9).toULongLong(); QString sBaseName = query.value(10).toString(); QDateTime dtProgStart = query.value(11).toDateTime(); QDateTime dtProgEnd = query.value(12).toDateTime(); QString sStorageGrp = query.value(13).toString(); // ---------------------------------------------------------------------- // Cache Host ip Address & Port // ---------------------------------------------------------------------- if (!m_mapBackendIp.contains( sHostName )) m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName); if (!m_mapBackendPort.contains( sHostName )) m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName); // ---------------------------------------------------------------------- // Build Support Strings // ---------------------------------------------------------------------- QString sName = sTitle + ": " + (sSubtitle.isEmpty() ? sDescription : sSubtitle); QString sURIBase = QString( "http://%1:%2/Myth/" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( m_mapBackendPort[ sHostName ] ); QString sURIParams = QString( "?ChanId=%1&StartTime=%2" ) .arg( nChanid ) .arg( dtStartTime.toString(Qt::ISODate)); QString sId = QString( "RecTv/0/item%1") .arg( sURIParams ); CDSObject *pItem = CDSObject::CreateVideoItem( sId, sName, sObjectId ); pItem->m_bRestricted = false; pItem->m_bSearchable = true; pItem->m_sWriteStatus = "WRITABLE"; if ( bAddRef ) { QString sRefId = QString( "%1/0/item%2") .arg( m_sExtensionId ) .arg( sURIParams ); pItem->SetPropValue( "refID", sRefId ); } pItem->SetPropValue( "genre" , sCategory ); pItem->SetPropValue( "longDescription", sDescription ); pItem->SetPropValue( "description" , sSubtitle ); //pItem->SetPropValue( "producer" , ); //pItem->SetPropValue( "rating" , ); //pItem->SetPropValue( "actor" , ); //pItem->SetPropValue( "director" , ); //pItem->SetPropValue( "publisher" , ); //pItem->SetPropValue( "language" , ); //pItem->SetPropValue( "relation" , ); //pItem->SetPropValue( "region" , ); // ---------------------------------------------------------------------- // Needed for Microsoft Media Player Compatibility // (Won't display correct Title without them) // ---------------------------------------------------------------------- pItem->SetPropValue( "creator" , "[Unknown Author]" ); pItem->SetPropValue( "artist" , "[Unknown Author]" ); pItem->SetPropValue( "album" , "[Unknown Series]" ); pItem->SetPropValue( "actor" , "[Unknown Author]" ); pItem->SetPropValue( "date" , dtStartTime.toString(Qt::ISODate)); pResults->Add( pItem ); // ---------------------------------------------------------------------- // Add Video Resource Element based on File contents/extension (HTTP) // ---------------------------------------------------------------------- StorageGroup sg(sStorageGrp, sHostName); QString sFilePath = sg.FindRecordingFile(sBaseName); QString sMimeType; if ( QFile::exists(sFilePath) ) sMimeType = HTTPRequest::TestMimeType( sFilePath ); else sMimeType = HTTPRequest::TestMimeType( sBaseName ); // If we are dealing with Window Media Player 12 (i.e. Windows 7) // then fake the Mime type to place the recorded TV in the // recorded TV section. if (pRequest->m_eClient == CDS_ClientWMP && pRequest->m_nClientVersion >= 12.0) { sMimeType = "video/x-ms-dvr"; } // DLNA string below is temp fix for ps3 seeking. QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType ); QString sURI = QString( "%1GetRecording%2").arg( sURIBase ) .arg( sURIParams ); Resource *pRes = pItem->AddResource( sProtocol, sURI ); uint uiStart = dtProgStart.toTime_t(); uint uiEnd = dtProgEnd.toTime_t(); uint uiDur = uiEnd - uiStart; QString sDur; sDur.sprintf("%02d:%02d:%02d", (uiDur / 3600) % 24, (uiDur / 60) % 60, uiDur % 60); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); /* // ---------------------------------------------------------------------- // Add Video Resource Element based on File extension (mythtv) // ---------------------------------------------------------------------- sProtocol = QString( "myth:*:%1:*" ).arg( sMimeType ); sURI = QString( "myth://%1/%2" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( sBaseName ); pRes = pItem->AddResource( sProtocol, sURI ); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); */ // ---------------------------------------------------------------------- // Add Preview URI as albumArt // ---------------------------------------------------------------------- sURI = QString( "%1GetPreviewImage%2%3").arg( sURIBase ) .arg( sURIParams ) .arg( "&Width=160" ); pItem->SetPropValue( "albumArtURI", sURI ); Property *pProp = pItem->GetProperty("albumArtURI"); if (pProp) { pProp->AddAttribute("dlna:profileID", "PNG_TN"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } }
/** \brief Try to get a lock on the table schemalock. * Prevents multiple upgrades by different programs of the same schema. */ bool DBUtil::TryLockSchema(MSqlQuery &query, uint timeout_secs) { query.prepare("SELECT GET_LOCK('schemaLock', :TIMEOUT)"); query.bindValue(":TIMEOUT", timeout_secs); return query.exec() && query.first() && query.value(0).toBool(); }
/// Sets metadata from a DB row void VideoMetadataImp::fromDBRow(MSqlQuery &query) { m_title = query.value(0).toString(); m_director = query.value(1).toString(); m_studio = query.value(2).toString(); m_plot = query.value(3).toString(); m_rating = query.value(4).toString(); m_year = query.value(5).toInt(); m_releasedate = query.value(6).toDate(); m_userrating = (float)query.value(7).toDouble(); if (isnan(m_userrating) || m_userrating < 0) m_userrating = 0.0; if (m_userrating > 10.0) m_userrating = 10.0; m_length = query.value(8).toInt(); m_filename = query.value(9).toString(); m_hash = query.value(10).toString(); m_showlevel = ParentalLevel(query.value(11).toInt()).GetLevel(); m_coverfile = query.value(12).toString(); m_inetref = query.value(13).toString(); m_homepage = query.value(14).toString(); m_childID = query.value(15).toUInt(); m_browse = query.value(16).toBool(); m_watched = query.value(17).toBool(); m_playcommand = query.value(18).toString(); m_categoryID = query.value(19).toInt(); m_id = query.value(20).toInt(); m_trailer = query.value(21).toString(); m_screenshot = query.value(22).toString(); m_banner = query.value(23).toString(); m_fanart = query.value(24).toString(); m_subtitle = query.value(25).toString(); m_tagline = query.value(26).toString(); m_season = query.value(27).toInt(); m_episode = query.value(28).toInt(); m_host = query.value(29).toString(); m_insertdate = query.value(30).toDate(); m_processed = query.value(31).toBool(); VideoCategory::GetCategory().get(m_categoryID, m_category); // Genres fillGenres(); //Countries fillCountries(); // Cast fillCast(); }
uint DBEvent::GetOverlappingPrograms( MSqlQuery &query, uint chanid, vector<DBEvent> &programs) const { uint count = 0; query.prepare( "SELECT title, subtitle, description, " " category, category_type, " " starttime, endtime, " " subtitletypes+0,audioprop+0, videoprop+0, " " seriesid, programid, " " partnumber, parttotal, " " syndicatedepisodenumber, " " airdate, originalairdate, " " previouslyshown,listingsource, " " stars+0 " "FROM program " "WHERE chanid = :CHANID AND " " manualid = 0 AND " " ( ( starttime >= :STIME1 AND starttime < :ETIME1 ) OR " " ( endtime > :STIME2 AND endtime <= :ETIME2 ) )"); query.bindValue(":CHANID", chanid); query.bindValue(":STIME1", starttime); query.bindValue(":ETIME1", endtime); query.bindValue(":STIME2", starttime); query.bindValue(":ETIME2", endtime); if (!query.exec()) { MythDB::DBError("GetOverlappingPrograms 1", query); return 0; } while (query.next()) { MythCategoryType category_type = string_to_myth_category_type(query.value(4).toString()); DBEvent prog( query.value(0).toString(), query.value(1).toString(), query.value(2).toString(), query.value(3).toString(), category_type, query.value(5).toDateTime(), query.value(6).toDateTime(), query.value(7).toUInt(), query.value(8).toUInt(), query.value(9).toUInt(), query.value(19).toDouble(), query.value(10).toString(), query.value(11).toString(), query.value(18).toUInt()); prog.partnumber = query.value(12).toUInt(); prog.parttotal = query.value(13).toUInt(); prog.syndicatedepisodenumber = query.value(14).toString(); prog.airdate = query.value(15).toUInt(); prog.originalairdate = query.value(16).toDate(); prog.previouslyshown = query.value(17).toBool(); ; programs.push_back(prog); count++; } return count; }
bool ProgramData::IsUnchanged( MSqlQuery &query, uint chanid, const ProgInfo &pi) { query.prepare( "SELECT count(*) " "FROM program " "WHERE chanid = :CHANID AND " " starttime = :START AND " " endtime = :END AND " " title = :TITLE AND " " subtitle = :SUBTITLE AND " " description = :DESC AND " " category = :CATEGORY AND " " category_type = :CATEGORY_TYPE AND " " airdate = :AIRDATE AND " " stars >= (:STARS1 - 0.001) AND " " stars <= (:STARS2 + 0.001) AND " " previouslyshown = :PREVIOUSLYSHOWN AND " " title_pronounce = :TITLE_PRONOUNCE AND " " audioprop = :AUDIOPROP AND " " videoprop = :VIDEOPROP AND " " subtitletypes = :SUBTYPES AND " " partnumber = :PARTNUMBER AND " " parttotal = :PARTTOTAL AND " " seriesid = :SERIESID AND " " showtype = :SHOWTYPE AND " " colorcode = :COLORCODE AND " " syndicatedepisodenumber = :SYNDICATEDEPISODENUMBER AND " " programid = :PROGRAMID"); QString cattype = myth_category_type_to_string(pi.categoryType); query.bindValue(":CHANID", chanid); query.bindValue(":START", pi.starttime); query.bindValue(":END", pi.endtime); query.bindValue(":TITLE", pi.title); query.bindValue(":SUBTITLE", pi.subtitle); query.bindValue(":DESC", pi.description); query.bindValue(":CATEGORY", pi.category); query.bindValue(":CATEGORY_TYPE", cattype); query.bindValue(":AIRDATE", pi.airdate); query.bindValue(":STARS1", pi.stars); query.bindValue(":STARS2", pi.stars); query.bindValue(":PREVIOUSLYSHOWN", pi.previouslyshown); query.bindValue(":TITLE_PRONOUNCE", pi.title_pronounce); query.bindValue(":AUDIOPROP", pi.audioProps); query.bindValue(":VIDEOPROP", pi.videoProps); query.bindValue(":SUBTYPES", pi.subtitleType); query.bindValue(":PARTNUMBER", pi.partnumber); query.bindValue(":PARTTOTAL", pi.parttotal); query.bindValue(":SERIESID", pi.seriesId); query.bindValue(":SHOWTYPE", pi.showtype); query.bindValue(":COLORCODE", pi.colorcode); query.bindValue(":SYNDICATEDEPISODENUMBER", pi.syndicatedepisodenumber); query.bindValue(":PROGRAMID", pi.programId); if (query.exec() && query.next()) return query.value(0).toUInt() > 0; return false; }
void UPnpCDSMusic::AddItem( const UPnpCDSRequest *pRequest, const QString &sObjectId, UPnpCDSExtensionResults *pResults, bool bAddRef, MSqlQuery &query ) { QString sName; int nId = query.value( 0).toInt(); QString sArtist = query.value( 1).toString(); QString sAlbum = query.value( 2).toString(); QString sTitle = query.value( 3).toString(); QString sGenre = query.value( 4).toString(); int nYear = query.value( 5).toInt(); int nTrackNum = query.value( 6).toInt(); QString sDescription = query.value( 7).toString(); QString sFileName = query.value( 8).toString(); uint nLength = query.value( 9).toInt(); uint64_t nFileSize = (quint64)query.value(10).toULongLong(); #if 0 if ((nNodeIdx == 0) || (nNodeIdx == 1)) { sName = QString( "%1-%2:%3" ) .arg( sArtist) .arg( sAlbum ) .arg( sTitle ); } else #endif sName = sTitle; // ---------------------------------------------------------------------- // Cache Host ip Address & Port // ---------------------------------------------------------------------- #if 0 if (!m_mapBackendIp.contains( sHostName )) m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName); if (!m_mapBackendPort.contains( sHostName )) m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName); #endif QString sServerIp = gCoreContext->GetSetting( "BackendServerIp" ); QString sPort = gCoreContext->GetSetting( "BackendStatusPort" ); // ---------------------------------------------------------------------- // Build Support Strings // ---------------------------------------------------------------------- QString sURIBase = QString( "http://%1:%2/Content/" ) .arg( sServerIp ) .arg( sPort ); QString sURIParams = QString( "?Id=%1" ) .arg( nId ); QString sId = QString( "Music/1/item%1") .arg( sURIParams ); CDSObject *pItem = CDSObject::CreateMusicTrack( sId, sName, sObjectId ); pItem->m_bRestricted = true; pItem->m_bSearchable = true; pItem->m_sWriteStatus = "NOT_WRITABLE"; if ( bAddRef ) { QString sRefId = QString( "%1/0/item%2") .arg( m_sExtensionId ) .arg( sURIParams ); pItem->SetPropValue( "refID", sRefId ); } pItem->SetPropValue( "genre" , sGenre ); pItem->SetPropValue( "description" , sTitle ); pItem->SetPropValue( "longDescription" , sDescription); pItem->SetPropValue( "artist" , sArtist ); pItem->SetPropValue( "album" , sAlbum ); pItem->SetPropValue( "originalTrackNumber" , QString::number(nTrackNum)); if (nYear > 0 && nYear < 9999) pItem->SetPropValue( "date", QDate(nYear,1,1).toString(Qt::ISODate)); #if 0 pObject->AddProperty( new Property( "publisher" , "dc" )); pObject->AddProperty( new Property( "language" , "dc" )); pObject->AddProperty( new Property( "relation" , "dc" )); pObject->AddProperty( new Property( "rights" , "dc" )); pObject->AddProperty( new Property( "playlist" , "upnp" )); pObject->AddProperty( new Property( "storageMedium" , "upnp" )); pObject->AddProperty( new Property( "contributor" , "dc" )); pObject->AddProperty( new Property( "date" , "dc" )); #endif QString sArtURI = QString( "%1GetAlbumArt?Id=%2").arg( sURIBase ) .arg( nId ); QList<Property*> propList = pItem->GetProperties("albumArtURI"); if (propList.size() >= 4) { // Prefer JPEG over PNG here, although PNG is allowed JPEG probably // has wider device support and crucially the filesizes are smaller // which speeds up loading times over the network // We MUST include the thumbnail size, but since some clients may use the // first image they see and the thumbnail is tiny, instead return the // medium first. The large could be very large, which is no good if the // client is pulling images for an entire list at once! // Medium Property *pProp = propList.at(0); if (pProp) { // Must be no more than 1024x768 pProp->m_sValue = sArtURI; pProp->m_sValue.append("&Width=1024&Height=768"); pProp->AddAttribute("dlna:profileID", "JPG_MED"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Thumbnail pProp = propList.at(1); if (pProp) { // At least one albumArtURI must be a ThumbNail (TN) no larger // than 160x160, and it must also be a jpeg pProp->m_sValue = sArtURI; pProp->m_sValue.append("&Width=160&Height=160"); pProp->AddAttribute("dlna:profileID", "JPG_TN"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Small pProp = propList.at(2); if (pProp) { // Must be no more than 640x480 pProp->m_sValue = sArtURI; pProp->m_sValue.append("&Width=640&Height=480"); pProp->AddAttribute("dlna:profileID", "JPG_SM"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Large pProp = propList.at(3); if (pProp) { // Must be no more than 4096x4096 - for our purposes, just return // a fullsize image pProp->m_sValue = sArtURI; pProp->AddAttribute("dlna:profileID", "JPG_LRG"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } } pResults->Add( pItem ); // ---------------------------------------------------------------------- // Add Music Resource Element based on File extension (HTTP) // ---------------------------------------------------------------------- QFileInfo fInfo( sFileName ); QString sMimeType = HTTPRequest::GetMimeType( fInfo.suffix() ); QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType ); QString sURI = QString( "%1GetMusic%2").arg( sURIBase ) .arg( sURIParams ); Resource *pRes = pItem->AddResource( sProtocol, sURI ); nLength /= 1000; QString sDur; sDur.sprintf("%02d:%02d:%02d", (nLength / 3600) % 24, (nLength / 60) % 60, nLength % 60); pRes->AddAttribute( "duration" , sDur ); if (nFileSize > 0) pRes->AddAttribute( "size" , QString::number( nFileSize) ); }
void UPnpCDSTv::AddItem( const UPnpCDSRequest *pRequest, const QString &sObjectId, UPnpCDSExtensionResults *pResults, bool bAddRef, MSqlQuery &query ) { int nChanid = query.value( 0).toInt(); QDateTime dtStartTime = MythDate::as_utc(query.value(1).toDateTime()); QDateTime dtEndTime = MythDate::as_utc(query.value(2).toDateTime()); QString sTitle = query.value( 3).toString(); QString sSubtitle = query.value( 4).toString(); QString sDescription = query.value( 5).toString(); QString sCategory = query.value( 6).toString(); QString sHostName = query.value( 7).toString(); QString sRecGroup = query.value( 8).toString(); uint64_t nFileSize = query.value( 9).toULongLong(); QString sBaseName = query.value(10).toString(); QDateTime dtProgStart = MythDate::as_utc(query.value(11).toDateTime()); QDateTime dtProgEnd = MythDate::as_utc(query.value(12).toDateTime()); QString sStorageGrp = query.value(13).toString(); QString sInetRef = query.value(14).toString(); // ---------------------------------------------------------------------- // Cache Host ip Address & Port // ---------------------------------------------------------------------- if (!m_mapBackendIp.contains( sHostName )) m_mapBackendIp[ sHostName ] = gCoreContext->GetBackendServerIP4(sHostName); if (!m_mapBackendPort.contains( sHostName )) m_mapBackendPort[ sHostName ] = gCoreContext->GetBackendStatusPort(sHostName); // ---------------------------------------------------------------------- // Build Support Strings // ---------------------------------------------------------------------- QString sName = sTitle + ": " + (sSubtitle.isEmpty() ? sDescription.left(128) : sSubtitle); QString sURIBase = QString( "http://%1:%2/Content/" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( m_mapBackendPort[ sHostName ] ); QString sURIParams = QString( "?ChanId=%1&StartTime=%2" ) .arg( nChanid ) .arg( dtStartTime.toString(Qt::ISODate)); QString sId = QString( "RecTv/0/item%1") .arg( sURIParams ); CDSObject *pItem = CDSObject::CreateVideoItem( sId, sName, sObjectId ); pItem->m_bRestricted = false; pItem->m_bSearchable = true; pItem->m_sWriteStatus = "WRITABLE"; if ( bAddRef ) { QString sRefId = QString( "%1/0/item%2") .arg( m_sExtensionId ) .arg( sURIParams ); pItem->SetPropValue( "refID", sRefId ); } pItem->SetPropValue( "genre" , sCategory ); pItem->SetPropValue( "longDescription", sDescription ); pItem->SetPropValue( "description" , sSubtitle ); //pItem->SetPropValue( "producer" , ); //pItem->SetPropValue( "rating" , ); //pItem->SetPropValue( "actor" , ); //pItem->SetPropValue( "director" , ); //pItem->SetPropValue( "publisher" , ); //pItem->SetPropValue( "language" , ); //pItem->SetPropValue( "relation" , ); //pItem->SetPropValue( "region" , ); // ---------------------------------------------------------------------- // Needed for Microsoft Media Player Compatibility // (Won't display correct Title without them) // ---------------------------------------------------------------------- pItem->SetPropValue( "creator" , "[Unknown Author]" ); pItem->SetPropValue( "artist" , "[Unknown Author]" ); pItem->SetPropValue( "album" , "[Unknown Series]" ); pItem->SetPropValue( "actor" , "[Unknown Author]" ); pItem->SetPropValue( "date" , dtStartTime.toString(Qt::ISODate)); pResults->Add( pItem ); // ---------------------------------------------------------------------- // Add Video Resource Element based on File contents/extension (HTTP) // ---------------------------------------------------------------------- StorageGroup sg(sStorageGrp, sHostName); QString sFilePath = sg.FindFile(sBaseName); QString sMimeType; if ( QFile::exists(sFilePath) ) sMimeType = HTTPRequest::TestMimeType( sFilePath ); else sMimeType = HTTPRequest::TestMimeType( sBaseName ); // If we are dealing with Window Media Player 12 (i.e. Windows 7) // then fake the Mime type to place the recorded TV in the // recorded TV section. if (pRequest->m_eClient == CDS_ClientWMP && pRequest->m_nClientVersion >= 12.0) { sMimeType = "video/x-ms-dvr"; } // If we are dealing with a Sony Blu-ray player then we fake the // MIME type to force the video to appear if ( pRequest->m_eClient == CDS_ClientSonyDB ) { sMimeType = "video/avi"; } // DLNA string below is temp fix for ps3 seeking. QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType ); QString sURI = QString( "%1GetRecording%2").arg( sURIBase ) .arg( sURIParams ); // Sony BDPS370 requires a DLNA Profile Name // FIXME: detection to determine the correct DLNA Profile Name if (sMimeType == "video/mpeg") { sProtocol += ";DLNA.ORG_PN=MPEG_TS_SD_NA_ISO"; } Resource *pRes = pItem->AddResource( sProtocol, sURI ); uint uiStart = dtProgStart.toTime_t(); uint uiEnd = dtProgEnd.toTime_t(); uint uiDur = uiEnd - uiStart; MSqlQuery query2(MSqlQuery::InitCon()); query2.prepare( "SELECT data FROM recordedmarkup WHERE chanid=:CHANID AND " "starttime=:STARTTIME AND type = 33" ); query2.bindValue(":CHANID", (int)nChanid); query2.bindValue(":STARTTIME", dtStartTime); if (query2.exec() && query2.next()) uiDur = query2.value(0).toUInt() / 1000; QString sDur; sDur.sprintf("%02d:%02d:%02d", (uiDur / 3600) % 24, (uiDur / 60) % 60, uiDur % 60); LOG(VB_UPNP, LOG_DEBUG, "Duration: " + sDur ); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); /* // ---------------------------------------------------------------------- // Add Video Resource Element based on File extension (mythtv) // ---------------------------------------------------------------------- sProtocol = QString( "myth:*:%1:*" ).arg( sMimeType ); sURI = QString( "myth://%1/%2" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( sBaseName ); pRes = pItem->AddResource( sProtocol, sURI ); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); */ // ---------------------------------------------------------------------- // Add Preview URI as <res> // MUST be _TN and 160px // ---------------------------------------------------------------------- sURI = QString( "%1GetPreviewImage%2%3").arg( sURIBase ) .arg( sURIParams ) .arg( "&Width=160" ); // TODO: Must be JPG for minimal compliance sProtocol = QString( "http-get:*:image/png:DLNA.ORG_PN=PNG_TN"); pItem->AddResource( sProtocol, sURI ); // ---------------------------------------------------------------------- // Add Artwork URI as albumArt // ---------------------------------------------------------------------- sURI = QString( "%1GetRecordingArtwork?Type=coverart&Inetref=%3") .arg( sURIBase ) .arg( sInetRef ); QList<Property*> propList = pItem->GetProperties("albumArtURI"); if (propList.size() >= 4) { // Prefer JPEG over PNG here, although PNG is allowed JPEG probably // has wider device support and crucially the filesizes are smaller // which speeds up loading times over the network // We MUST include the thumbnail size, but since some clients may use the // first image they see and the thumbnail is tiny, instead return the // medium first. The large could be very large, which is no good if the // client is pulling images for an entire list at once! // Medium Property *pProp = propList.at(0); if (pProp) { // Must be no more than 1024x768 pProp->m_sValue = sURI; pProp->m_sValue.append("&Width=1024&Height=768"); pProp->AddAttribute("dlna:profileID", "JPG_MED"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Thumbnail pProp = propList.at(1); if (pProp) { // At least one albumArtURI must be a ThumbNail (TN) no larger // than 160x160, and it must also be a jpeg pProp->m_sValue = sURI; pProp->m_sValue.append("&Width=160&Height=160"); pProp->AddAttribute("dlna:profileID", "JPG_TN"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Medium pProp = propList.at(2); if (pProp) { // Must be no more than 1024x768 pProp->m_sValue = sURI; pProp->m_sValue.append("&Width=1024&Height=768"); pProp->AddAttribute("dlna:profileID", "JPG_MED"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Large pProp = propList.at(3); if (pProp) { // Must be no more than 4096x4096 - for our purposes, just return // a fullsize image pProp->m_sValue = sURI; pProp->AddAttribute("dlna:profileID", "JPG_LRG"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } } }
void UPnpCDSMusic::AddItem( const UPnpCDSRequest *pRequest, const QString &sObjectId, UPnpCDSExtensionResults *pResults, bool bAddRef, MSqlQuery &query ) { QString sName; int nId = query.value( 0).toInt(); QString sArtist = query.value( 1).toString(); QString sAlbum = query.value( 2).toString(); QString sTitle = query.value( 3).toString(); QString sGenre = query.value( 4).toString(); // int nYear = query.value( 5).toInt(); int nTrackNum = query.value( 6).toInt(); QString sDescription = query.value( 7).toString(); QString sFileName = query.value( 8).toString(); uint nLength = query.value( 9).toInt(); /* if ((nNodeIdx == 0) || (nNodeIdx == 1)) { sName = QString( "%1-%2:%3" ) .arg( sArtist) .arg( sAlbum ) .arg( sTitle ); } else */ sName = sTitle; //cout << nId << " " << sName << endl; // ---------------------------------------------------------------------- // Cache Host ip Address & Port // ---------------------------------------------------------------------- // if (!m_mapBackendIp.contains( sHostName )) // m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName); // // if (!m_mapBackendPort.contains( sHostName )) // m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName); QString sServerIp = gCoreContext->GetSetting( "BackendServerIp" ); QString sPort = gCoreContext->GetSetting( "BackendStatusPort" ); // ---------------------------------------------------------------------- // Build Support Strings // ---------------------------------------------------------------------- QString sURIBase = QString( "http://%1:%2/Myth/" ) .arg( sServerIp ) .arg( sPort ); QString sURIParams = QString( "?Id=%1" ) .arg( nId ); QString sId = QString( "Music/1/item%1") .arg( sURIParams ); CDSObject *pItem = CDSObject::CreateMusicTrack( sId, sName, sObjectId ); pItem->m_bRestricted = true; pItem->m_bSearchable = true; pItem->m_sWriteStatus = "NOT_WRITABLE"; if ( bAddRef ) { QString sRefId = QString( "%1/0/item%2") .arg( m_sExtensionId ) .arg( sURIParams ); pItem->SetPropValue( "refID", sRefId ); } pItem->SetPropValue( "genre" , sGenre ); pItem->SetPropValue( "description" , sTitle ); pItem->SetPropValue( "longDescription" , sDescription); pItem->SetPropValue( "artist" , sArtist ); pItem->SetPropValue( "album" , sAlbum ); pItem->SetPropValue( "originalTrackNumber" , QString::number( nTrackNum )); /* pObject->AddProperty( new Property( "publisher" , "dc" )); pObject->AddProperty( new Property( "language" , "dc" )); pObject->AddProperty( new Property( "relation" , "dc" )); pObject->AddProperty( new Property( "rights" , "dc" )); pObject->AddProperty( new Property( "playlist" , "upnp" )); pObject->AddProperty( new Property( "storageMedium" , "upnp" )); pObject->AddProperty( new Property( "contributor" , "dc" )); pObject->AddProperty( new Property( "date" , "dc" )); */ pResults->Add( pItem ); // ---------------------------------------------------------------------- // Add Music Resource Element based on File extension (HTTP) // ---------------------------------------------------------------------- QFileInfo fInfo( sFileName ); QString sMimeType = HTTPRequest::GetMimeType( fInfo.suffix() ); QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType ); QString sURI = QString( "%1GetMusic%2").arg( sURIBase ) .arg( sURIParams ); Resource *pRes = pItem->AddResource( sProtocol, sURI ); nLength /= 1000; QString sDur; sDur.sprintf("%02d:%02d:%02d", (nLength / 3600) % 24, (nLength / 60) % 60, nLength % 60); pRes->AddAttribute( "duration" , sDur ); }