void CGUIDialogVideoBookmarks::AddBookmark(CVideoInfoTag* tag) { CVideoDatabase videoDatabase; CBookmark bookmark; bookmark.timeInSeconds = (int)g_application.GetTime(); bookmark.totalTimeInSeconds = (int)g_application.GetTotalTime(); if( g_application.m_pPlayer ) bookmark.playerState = g_application.m_pPlayer->GetPlayerState(); else bookmark.playerState.Empty(); bookmark.player = CPlayerCoreFactory::GetPlayerName(g_application.GetCurrentPlayer()); // create the thumbnail image #ifdef HAS_VIDEO_PLAYBACK float aspectRatio = g_renderManager.GetAspectRatio(); #else float aspectRatio = 1.0f; #endif int width = BOOKMARK_THUMB_WIDTH; int height = (int)(BOOKMARK_THUMB_WIDTH / aspectRatio); if (height > BOOKMARK_THUMB_WIDTH) { height = BOOKMARK_THUMB_WIDTH; width = (int)(BOOKMARK_THUMB_WIDTH * aspectRatio); } { #ifdef HAS_VIDEO_PLAYBACK CRenderCapture* thumbnail = g_renderManager.AllocRenderCapture(); g_renderManager.Capture(thumbnail, width, height, CAPTUREFLAG_IMMEDIATELY); if (thumbnail->GetUserState() == CAPTURESTATE_DONE) { Crc32 crc; crc.ComputeFromLowerCase(g_application.CurrentFile()); bookmark.thumbNailImage.Format("%08x_%i.jpg", (unsigned __int32) crc, m_vecItems->Size() + 1); bookmark.thumbNailImage = URIUtils::AddFileToFolder(g_settings.GetBookmarksThumbFolder(), bookmark.thumbNailImage); if (!CPicture::CreateThumbnailFromSurface(thumbnail->GetPixels(), width, height, thumbnail->GetWidth() * 4, bookmark.thumbNailImage)) bookmark.thumbNailImage.Empty(); } else CLog::Log(LOGERROR,"CGUIDialogVideoBookmarks: failed to create thumbnail"); g_renderManager.ReleaseRenderCapture(thumbnail); #endif } videoDatabase.Open(); if (tag) videoDatabase.AddBookMarkForEpisode(*tag, bookmark); else videoDatabase.AddBookMarkToFile(g_application.CurrentFile(), bookmark, CBookmark::STANDARD); videoDatabase.Close(); Update(); }
void CGUIDialogVideoBookmarks::AddBookmark(CVideoInfoTag* tag) { CVideoDatabase videoDatabase; CBookmark bookmark; bookmark.timeInSeconds = (int)g_application.GetTime(); bookmark.totalTimeInSeconds = (int)g_application.GetTotalTime(); if( g_application.m_pPlayer ) bookmark.playerState = g_application.m_pPlayer->GetPlayerState(); else bookmark.playerState.Empty(); bookmark.player = CPlayerCoreFactory::GetPlayerName(g_application.GetCurrentPlayer()); // create the thumbnail image #ifdef HAS_VIDEO_PLAYBACK float aspectRatio = g_renderManager.GetAspectRatio(); #else float aspectRatio = 1.0f; #endif int width = BOOKMARK_THUMB_WIDTH; int height = (int)(BOOKMARK_THUMB_WIDTH / aspectRatio); if (height > BOOKMARK_THUMB_WIDTH) { height = BOOKMARK_THUMB_WIDTH; width = (int)(BOOKMARK_THUMB_WIDTH * aspectRatio); } { CSingleLock lock(g_graphicsContext); // we're really just using the CTexture here as a pixel buffer CTexture texture(width, height, XB_FMT_B8G8R8A8); #ifdef HAS_VIDEO_PLAYBACK //g_renderManager.CreateThumbnail(&texture, width, height); #endif Crc32 crc; crc.ComputeFromLowerCase(g_application.CurrentFile()); bookmark.thumbNailImage.Format("%08x_%i.jpg", (unsigned __int32) crc, m_vecItems->Size() + 1); bookmark.thumbNailImage = CUtil::AddFileToFolder(g_settings.GetBookmarksThumbFolder(), bookmark.thumbNailImage); if (!CPicture::CreateThumbnailFromSurface(texture.GetPixels(), width, height, texture.GetPitch(), bookmark.thumbNailImage)) bookmark.thumbNailImage.Empty(); } videoDatabase.Open(); if (tag) videoDatabase.AddBookMarkForEpisode(*tag, bookmark); else videoDatabase.AddBookMarkToFile(g_application.CurrentFile(), bookmark, CBookmark::STANDARD); videoDatabase.Close(); Update(); }
void CVideoLibrary::UpdateResumePoint(const CVariant ¶meterObject, CVideoInfoTag &details, CVideoDatabase &videodatabase) { if (!parameterObject["resume"].isNull()) { CBookmark bookmark; videodatabase.GetResumeBookMark(details.m_strFileNameAndPath, bookmark); int position = (int)parameterObject["resume"]["position"].asInteger(); int total = (int)parameterObject["resume"]["total"].asInteger(); if (position == 0) videodatabase.ClearBookMarksOfFile(details.m_strFileNameAndPath, CBookmark::RESUME); else { bookmark.timeInSeconds = position; if (total > 0) bookmark.totalTimeInSeconds = total; videodatabase.AddBookMarkToFile(details.m_strFileNameAndPath, bookmark, CBookmark::RESUME); } } }
CStdString CGUIWindowPVRRecordings::GetResumeString(const CFileItem& item) { CStdString resumeString; if (item.IsPVRRecording()) { // First try to find the resume position on the back-end, if that fails use video database int positionInSeconds = item.GetPVRRecordingInfoTag()->GetLastPlayedPosition(); // If the back-end does report a saved position then make sure there is a corresponding resume bookmark if (positionInSeconds > 0) { CBookmark bookmark; bookmark.timeInSeconds = positionInSeconds; bookmark.totalTimeInSeconds = (double)item.GetPVRRecordingInfoTag()->GetDuration(); CVideoDatabase db; if (db.Open()) { CStdString itemPath(item.GetPVRRecordingInfoTag()->m_strFileNameAndPath); db.AddBookMarkToFile(itemPath, bookmark, CBookmark::RESUME); db.Close(); } } else if (positionInSeconds < 0) { CVideoDatabase db; if (db.Open()) { CBookmark bookmark; CStdString itemPath(item.GetPVRRecordingInfoTag()->m_strFileNameAndPath); if (db.GetResumeBookMark(itemPath, bookmark) ) positionInSeconds = lrint(bookmark.timeInSeconds); db.Close(); } } // Suppress resume from 0 if (positionInSeconds > 0) resumeString.Format(g_localizeStrings.Get(12022).c_str(), StringUtils::SecondsToTimeString(positionInSeconds).c_str()); } return resumeString; }
bool CGUIDialogVideoBookmarks::AddBookmark(CVideoInfoTag* tag) { CVideoDatabase videoDatabase; CBookmark bookmark; bookmark.timeInSeconds = (int)g_application.GetTime(); bookmark.totalTimeInSeconds = (int)g_application.GetTotalTime(); if( g_application.m_pPlayer->HasPlayer() ) bookmark.playerState = g_application.m_pPlayer->GetPlayerState(); else bookmark.playerState.clear(); bookmark.player = g_application.GetCurrentPlayer(); // create the thumbnail image float aspectRatio = g_application.m_pPlayer->GetRenderAspectRatio(); int width = BOOKMARK_THUMB_WIDTH; int height = (int)(BOOKMARK_THUMB_WIDTH / aspectRatio); if (height > (int)BOOKMARK_THUMB_WIDTH) { height = BOOKMARK_THUMB_WIDTH; width = (int)(BOOKMARK_THUMB_WIDTH * aspectRatio); } uint8_t *pixels = (uint8_t*)malloc(height * width * 4); unsigned int captureId = g_application.m_pPlayer->RenderCaptureAlloc(); g_application.m_pPlayer->RenderCapture(captureId, width, height, CAPTUREFLAG_IMMEDIATELY); bool hasImage = g_application.m_pPlayer->RenderCaptureGetPixels(captureId, 1000, pixels, height * width * 4); if (hasImage) { auto crc = Crc32::ComputeFromLowerCase(g_application.CurrentFile()); bookmark.thumbNailImage = StringUtils::Format("%08x_%i.jpg", crc, (int)bookmark.timeInSeconds); bookmark.thumbNailImage = URIUtils::AddFileToFolder(CProfilesManager::GetInstance().GetBookmarksThumbFolder(), bookmark.thumbNailImage); if (!CPicture::CreateThumbnailFromSurface(pixels, width, height, width * 4, bookmark.thumbNailImage)) { bookmark.thumbNailImage.clear(); } else CLog::Log(LOGERROR,"CGUIDialogVideoBookmarks: failed to create thumbnail"); g_application.m_pPlayer->RenderCaptureRelease(captureId); } else CLog::Log(LOGERROR,"CGUIDialogVideoBookmarks: failed to create thumbnail 2"); free(pixels); videoDatabase.Open(); if (tag) videoDatabase.AddBookMarkForEpisode(*tag, bookmark); else { std::string path = g_application.CurrentFile(); if (g_application.CurrentFileItem().HasProperty("original_listitem_url") && !URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString())) path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString(); videoDatabase.AddBookMarkToFile(path, bookmark, CBookmark::STANDARD); } videoDatabase.Close(); return true; }
void CSaveFileState::DoWork(CFileItem& item, CBookmark& bookmark, bool updatePlayCount) { std::string progressTrackingFile = item.GetPath(); if (item.HasVideoInfoTag() && StringUtils::StartsWith(item.GetVideoInfoTag()->m_strFileNameAndPath, "removable://")) progressTrackingFile = item.GetVideoInfoTag()->m_strFileNameAndPath; // this variable contains removable:// suffixed by disc label+uniqueid or is empty if label not uniquely identified else if (item.HasProperty("original_listitem_url")) { // only use original_listitem_url for Python, UPnP and Bluray sources std::string original = item.GetProperty("original_listitem_url").asString(); if (URIUtils::IsPlugin(original) || URIUtils::IsUPnP(original) || URIUtils::IsBluray(item.GetPath())) progressTrackingFile = original; } if (!progressTrackingFile.empty()) { #ifdef HAS_UPNP // checks if UPnP server of this file is available and supports updating if (URIUtils::IsUPnP(progressTrackingFile) && UPNP::CUPnP::SaveFileState(item, bookmark, updatePlayCount)) { return; } #endif if (item.IsVideo()) { std::string redactPath = CURL::GetRedacted(progressTrackingFile); CLog::Log(LOGDEBUG, "%s - Saving file state for video item %s", __FUNCTION__, redactPath.c_str()); CVideoDatabase videodatabase; if (!videodatabase.Open()) { CLog::Log(LOGWARNING, "%s - Unable to open video database. Can not save file state!", __FUNCTION__); } else { if (URIUtils::IsPlugin(progressTrackingFile) && !(item.HasVideoInfoTag() && item.GetVideoInfoTag()->m_iDbId >= 0)) { // FileItem from plugin can lack information, make sure all needed fields are set CVideoInfoTag *tag = item.GetVideoInfoTag(); CStreamDetails streams = tag->m_streamDetails; if (videodatabase.LoadVideoInfo(progressTrackingFile, *tag)) { item.SetPath(progressTrackingFile); item.ClearProperty("original_listitem_url"); tag->m_streamDetails = streams; } } bool updateListing = false; // No resume & watched status for livetv if (!item.IsLiveTV()) { if (updatePlayCount) { // no watched for not yet finished pvr recordings if (!item.IsInProgressPVRRecording()) { CLog::Log(LOGDEBUG, "%s - Marking video item %s as watched", __FUNCTION__, redactPath.c_str()); // consider this item as played videodatabase.IncrementPlayCount(item); item.GetVideoInfoTag()->IncrementPlayCount(); item.SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, true); updateListing = true; if (item.HasVideoInfoTag()) { CVariant data; data["id"] = item.GetVideoInfoTag()->m_iDbId; data["type"] = item.GetVideoInfoTag()->m_type; ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnUpdate", data); } } } else videodatabase.UpdateLastPlayed(item); if (!item.HasVideoInfoTag() || item.GetVideoInfoTag()->GetResumePoint().timeInSeconds != bookmark.timeInSeconds) { if (bookmark.timeInSeconds <= 0.0f) videodatabase.ClearBookMarksOfFile(progressTrackingFile, CBookmark::RESUME); else videodatabase.AddBookMarkToFile(progressTrackingFile, bookmark, CBookmark::RESUME); if (item.HasVideoInfoTag()) item.GetVideoInfoTag()->SetResumePoint(bookmark); // UPnP announce resume point changes to clients // however not if playcount is modified as that already announces if (item.HasVideoInfoTag() && !updatePlayCount) { CVariant data; data["id"] = item.GetVideoInfoTag()->m_iDbId; data["type"] = item.GetVideoInfoTag()->m_type; ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnUpdate", data); } updateListing = true; } } if (item.HasVideoInfoTag() && item.GetVideoInfoTag()->HasStreamDetails()) { CFileItem dbItem(item); // Check whether the item's db streamdetails need updating if (!videodatabase.GetStreamDetails(dbItem) || dbItem.GetVideoInfoTag()->m_streamDetails != item.GetVideoInfoTag()->m_streamDetails) { videodatabase.SetStreamDetailsForFile(item.GetVideoInfoTag()->m_streamDetails, progressTrackingFile); updateListing = true; } } // Could be part of an ISO stack. In this case the bookmark is saved onto the part. // In order to properly update the list, we need to refresh the stack's resume point CApplicationStackHelper& stackHelper = g_application.GetAppStackHelper(); if (stackHelper.HasRegisteredStack(item) && stackHelper.GetRegisteredStackTotalTimeMs(item) == 0) videodatabase.GetResumePoint(*(stackHelper.GetRegisteredStack(item)->GetVideoInfoTag())); videodatabase.Close(); if (updateListing) { CUtil::DeleteVideoDatabaseDirectoryCache(); CFileItemPtr msgItem(new CFileItem(item)); if (item.HasProperty("original_listitem_url")) msgItem->SetPath(item.GetProperty("original_listitem_url").asString()); CGUIMessage message(GUI_MSG_NOTIFY_ALL, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow(), 0, GUI_MSG_UPDATE_ITEM, 0, msgItem); CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message); } } } if (item.IsAudio()) { std::string redactPath = CURL::GetRedacted(progressTrackingFile); CLog::Log(LOGDEBUG, "%s - Saving file state for audio item %s", __FUNCTION__, redactPath.c_str()); CMusicDatabase musicdatabase; if (updatePlayCount) { if (!musicdatabase.Open()) { CLog::Log(LOGWARNING, "%s - Unable to open music database. Can not save file state!", __FUNCTION__); } else { // consider this item as played CLog::Log(LOGDEBUG, "%s - Marking audio item %s as listened", __FUNCTION__, redactPath.c_str()); musicdatabase.IncrementPlayCount(item); musicdatabase.Close(); // UPnP announce resume point changes to clients // however not if playcount is modified as that already announces if (item.IsMusicDb()) { CVariant data; data["id"] = item.GetMusicInfoTag()->GetDatabaseId(); data["type"] = item.GetMusicInfoTag()->GetType(); ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::AudioLibrary, "xbmc", "OnUpdate", data); } } } if (item.IsAudioBook()) { musicdatabase.Open(); musicdatabase.SetResumeBookmarkForAudioBook(item, item.m_lStartOffset + CUtil::ConvertSecsToMilliSecs(bookmark.timeInSeconds)); musicdatabase.Close(); } } } }
bool CGUIDialogVideoBookmarks::AddBookmark(CVideoInfoTag* tag) { CVideoDatabase videoDatabase; CBookmark bookmark; bookmark.timeInSeconds = (int)g_application.GetTime(); bookmark.totalTimeInSeconds = (int)g_application.GetTotalTime(); if( g_application.m_pPlayer->HasPlayer() ) bookmark.playerState = g_application.m_pPlayer->GetPlayerState(); else bookmark.playerState.clear(); bookmark.player = CPlayerCoreFactory::Get().GetPlayerName(g_application.GetCurrentPlayer()); // create the thumbnail image #ifdef HAS_VIDEO_PLAYBACK float aspectRatio = g_renderManager.GetAspectRatio(); #else float aspectRatio = 1.0f; #endif int width = BOOKMARK_THUMB_WIDTH; int height = (int)(BOOKMARK_THUMB_WIDTH / aspectRatio); if (height > (int)BOOKMARK_THUMB_WIDTH) { height = BOOKMARK_THUMB_WIDTH; width = (int)(BOOKMARK_THUMB_WIDTH * aspectRatio); } { #ifdef HAS_VIDEO_PLAYBACK CRenderCapture* thumbnail = g_renderManager.AllocRenderCapture(); if (thumbnail) { g_renderManager.Capture(thumbnail, width, height, CAPTUREFLAG_IMMEDIATELY); if (thumbnail->GetUserState() == CAPTURESTATE_DONE) { Crc32 crc; crc.ComputeFromLowerCase(g_application.CurrentFile()); bookmark.thumbNailImage = StringUtils::Format("%08x_%i.jpg", (unsigned __int32) crc, (int)bookmark.timeInSeconds); bookmark.thumbNailImage = URIUtils::AddFileToFolder(CProfilesManager::Get().GetBookmarksThumbFolder(), bookmark.thumbNailImage); if (!CPicture::CreateThumbnailFromSurface(thumbnail->GetPixels(), width, height, thumbnail->GetWidth() * 4, bookmark.thumbNailImage)) bookmark.thumbNailImage.clear(); } else CLog::Log(LOGERROR,"CGUIDialogVideoBookmarks: failed to create thumbnail"); g_renderManager.ReleaseRenderCapture(thumbnail); } #endif } videoDatabase.Open(); if (tag) videoDatabase.AddBookMarkForEpisode(*tag, bookmark); else { std::string path = g_application.CurrentFile(); if (g_application.CurrentFileItem().HasProperty("original_listitem_url") && !URIUtils::IsVideoDb(g_application.CurrentFileItem().GetProperty("original_listitem_url").asString())) path = g_application.CurrentFileItem().GetProperty("original_listitem_url").asString(); videoDatabase.AddBookMarkToFile(path, bookmark, CBookmark::STANDARD); } videoDatabase.Close(); return true; }
bool CSaveFileStateJob::DoWork() { std::string progressTrackingFile = m_item.GetPath(); if (m_item.HasVideoInfoTag() && StringUtils::StartsWith(m_item.GetVideoInfoTag()->m_strFileNameAndPath, "removable://")) progressTrackingFile = m_item.GetVideoInfoTag()->m_strFileNameAndPath; // this variable contains removable:// suffixed by disc label+uniqueid or is empty if label not uniquely identified else if (m_item.HasProperty("original_listitem_url")) { // only use original_listitem_url for Python, UPnP and Bluray sources std::string original = m_item.GetProperty("original_listitem_url").asString(); if (URIUtils::IsPlugin(original) || URIUtils::IsUPnP(original) || URIUtils::IsBluray(m_item.GetPath())) progressTrackingFile = original; } if (progressTrackingFile != "") { #ifdef HAS_UPNP // checks if UPnP server of this file is available and supports updating if (URIUtils::IsUPnP(progressTrackingFile) && UPNP::CUPnP::SaveFileState(m_item, m_bookmark, m_updatePlayCount)) { return true; } #endif if (m_item.IsVideo()) { std::string redactPath = CURL::GetRedacted(progressTrackingFile); CLog::Log(LOGDEBUG, "%s - Saving file state for video item %s", __FUNCTION__, redactPath.c_str()); CVideoDatabase videodatabase; if (!videodatabase.Open()) { CLog::Log(LOGWARNING, "%s - Unable to open video database. Can not save file state!", __FUNCTION__); } else { bool updateListing = false; // No resume & watched status for livetv if (!m_item.IsLiveTV()) { if (m_updatePlayCount) { CLog::Log(LOGDEBUG, "%s - Marking video item %s as watched", __FUNCTION__, redactPath.c_str()); // consider this item as played videodatabase.IncrementPlayCount(m_item); m_item.GetVideoInfoTag()->m_playCount++; // PVR: Set recording's play count on the backend (if supported) if (m_item.HasPVRRecordingInfoTag()) m_item.GetPVRRecordingInfoTag()->IncrementPlayCount(); m_item.SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, true); updateListing = true; } else videodatabase.UpdateLastPlayed(m_item); if (!m_item.HasVideoInfoTag() || m_item.GetVideoInfoTag()->m_resumePoint.timeInSeconds != m_bookmark.timeInSeconds) { if (m_bookmark.timeInSeconds <= 0.0f) videodatabase.ClearBookMarksOfFile(progressTrackingFile, CBookmark::RESUME); else videodatabase.AddBookMarkToFile(progressTrackingFile, m_bookmark, CBookmark::RESUME); if (m_item.HasVideoInfoTag()) m_item.GetVideoInfoTag()->m_resumePoint = m_bookmark; // PVR: Set/clear recording's resume bookmark on the backend (if supported) if (m_item.HasPVRRecordingInfoTag()) { PVR::CPVRRecordingPtr recording = m_item.GetPVRRecordingInfoTag(); recording->SetLastPlayedPosition(m_bookmark.timeInSeconds <= 0.0f ? 0 : (int)m_bookmark.timeInSeconds); recording->m_resumePoint = m_bookmark; } // UPnP announce resume point changes to clients // however not if playcount is modified as that already announces if (m_item.IsVideoDb() && !m_updatePlayCount) { CVariant data; data["id"] = m_item.GetVideoInfoTag()->m_iDbId; data["type"] = m_item.GetVideoInfoTag()->m_type; ANNOUNCEMENT::CAnnouncementManager::Get().Announce(ANNOUNCEMENT::VideoLibrary, "xbmc", "OnUpdate", data); } updateListing = true; } } if (m_videoSettings != CMediaSettings::Get().GetDefaultVideoSettings()) { videodatabase.SetVideoSettings(progressTrackingFile, m_videoSettings); } if (m_item.HasVideoInfoTag() && m_item.GetVideoInfoTag()->HasStreamDetails()) { CFileItem dbItem(m_item); // Check whether the item's db streamdetails need updating if (!videodatabase.GetStreamDetails(dbItem) || dbItem.GetVideoInfoTag()->m_streamDetails != m_item.GetVideoInfoTag()->m_streamDetails) { videodatabase.SetStreamDetailsForFile(m_item.GetVideoInfoTag()->m_streamDetails, progressTrackingFile); updateListing = true; } } // in order to properly update the the list, we need to update the stack item which is held in g_application.m_stackFileItemToUpdate if (m_item.HasProperty("stackFileItemToUpdate")) { m_item = m_item_discstack; // as of now, the item is replaced by the discstack item videodatabase.GetResumePoint(*m_item.GetVideoInfoTag()); } videodatabase.Close(); if (updateListing) { CUtil::DeleteVideoDatabaseDirectoryCache(); CFileItemPtr msgItem(new CFileItem(m_item)); if (m_item.HasProperty("original_listitem_url")) msgItem->SetPath(m_item.GetProperty("original_listitem_url").asString()); CGUIMessage message(GUI_MSG_NOTIFY_ALL, g_windowManager.GetActiveWindow(), 0, GUI_MSG_UPDATE_ITEM, 1, msgItem); // 1 to update the listing as well g_windowManager.SendThreadMessage(message); } } } if (m_item.IsAudio()) { std::string redactPath = CURL::GetRedacted(progressTrackingFile); CLog::Log(LOGDEBUG, "%s - Saving file state for audio item %s", __FUNCTION__, redactPath.c_str()); if (m_updatePlayCount) { #if 0 // Can't write to the musicdatabase while scanning for music info CGUIDialogMusicScan *dialog = (CGUIDialogMusicScan *)g_windowManager.GetWindow(WINDOW_DIALOG_MUSIC_SCAN); if (dialog && !dialog->IsDialogRunning()) #endif { CMusicDatabase musicdatabase; if (!musicdatabase.Open()) { CLog::Log(LOGWARNING, "%s - Unable to open music database. Can not save file state!", __FUNCTION__); } else { // consider this item as played CLog::Log(LOGDEBUG, "%s - Marking audio item %s as listened", __FUNCTION__, redactPath.c_str()); musicdatabase.IncrementPlayCount(m_item); musicdatabase.Close(); } } } } } return true; }