Repository: xbmc/xbmc
File: xbmc/utils/SaveFileStateJob.cpp (C++)

Code before:

          // Check whether the item's db streamdetails need updating
          if (!videodatabase.GetStreamDetails(dbItem) ||
              dbItem.GetVideoInfoTag()->m_streamDetails != item.GetVideoInfoTag()->m_streamDetails)
          {
            videoDbSuccess = videodatabase.SetStreamDetailsForFile(
                item.GetVideoInfoTag()->m_streamDetails, progressTrackingFile);
            updateListing = !videoDbSuccess;
          }
        }

        if (videoDbSuccess)
          videodatabase.CommitTransaction();
        else
          videodatabase.RollbackTransaction();
        videodatabase.BeginTransaction();
        videoDbSuccess = true;

        // See if fileId needs updating
        if (item.HasVideoInfoTag() && URIUtils::IsBluray(item.GetDynPath()))
        {
          if (item.GetVideoContentType() == VideoDbContentType::MOVIES)
          {
            const CVideoInfoTag* tag{item.GetVideoInfoTag()};
            if (tag->m_strFileNameAndPath != item.GetDynPath())
              videoDbSuccess = videodatabase.SetFileForMovie(item.GetDynPath(), tag->m_iDbId);
          }
          else if (item.GetVideoContentType() == VideoDbContentType::EPISODES)
          {
            const CVideoInfoTag* tag{item.GetVideoInfoTag()};
            if (tag->m_strFileNameAndPath != item.GetDynPath())
              videoDbSuccess = videodatabase.SetFileForEpisode(item.GetDynPath(), tag->m_iDbId);
          }
        }

        if (videoDbSuccess)
          videodatabase.CommitTransaction();
        else
          videodatabase.RollbackTransaction();

        if (updateListing)
        {
          CUtil::DeleteVideoDatabaseDirectoryCache();
          CFileItemPtr msgItem(new CFileItem(item));
          if (item.HasProperty("original_listitem_url"))
            msgItem->SetPath(item.GetProperty("original_listitem_url").asString());

          // 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
          const auto& components = CServiceBroker::GetAppComponents();
          const auto stackHelper = components.GetComponent<CApplicationStackHelper>();

Review comment (suggestion):
I took a look and looks like we can rely on tag->m_iFileId for the originally played file. It's key to pass that value to SetFileForMovie because there is no guarantee that what was played was the default version of a movie, and that we can get to the idFile from the idMovie.
The current GUI makes this case difficult to reach, but that could change. Here is a way: add a bluray to library (don't play it yet), add another movie or bluray. Make the first bluray a version of the second. It means that the first bluray is not the default version. Play the first bluray through the version picker dialog or the versions as folder view. Pick a playlist or menu from the playlist selection dialog. Later in SaveFileState we'll want to update the bluray file of the version from xxxx\index.bdmv to a bluray:// file. That's the videoversion record, not the filed stored in the movie table.

Code after:

          // Check whether the item's db streamdetails need updating
          if (!videodatabase.GetStreamDetails(dbItem) ||
              dbItem.GetVideoInfoTag()->m_streamDetails != item.GetVideoInfoTag()->m_streamDetails)
          {
            videoDbSuccess = videodatabase.SetStreamDetailsForFile(
                item.GetVideoInfoTag()->m_streamDetails, progressTrackingFile);
            updateListing = !videoDbSuccess;
          }
        }

        if (videoDbSuccess)
          videodatabase.CommitTransaction();
        else
          videodatabase.RollbackTransaction();
        videodatabase.BeginTransaction();
        videoDbSuccess = true;

        // See if idFile needs updating
        if (item.HasVideoInfoTag() && URIUtils::IsBlurayPath(item.GetDynPath()))
        {
          if (item.GetVideoContentType() == VideoDbContentType::MOVIES)
          {
            const CVideoInfoTag* tag{item.GetVideoInfoTag()};
            if (tag->m_strFileNameAndPath != item.GetDynPath())
              // tag->m_iFileId contains the idFile played and may be different to the idFile in the movie table entry if it's
              // a non-default video version
              videoDbSuccess =
                  videodatabase.SetFileForMovie(item.GetDynPath(), tag->m_iDbId, tag->m_iFileId);
          }
          else if (item.GetVideoContentType() == VideoDbContentType::EPISODES)
          {
            const CVideoInfoTag* tag{item.GetVideoInfoTag()};
            if (tag->m_strFileNameAndPath != item.GetDynPath())
              videoDbSuccess =
                  videodatabase.SetFileForEpisode(item.GetDynPath(), tag->m_iDbId, tag->m_iFileId);
          }
        }

        if (videoDbSuccess)
          videodatabase.CommitTransaction();
        else
          videodatabase.RollbackTransaction();

        if (updateListing)
        {
          CUtil::DeleteVideoDatabaseDirectoryCache();
          CFileItemPtr msgItem(new CFileItem(item));
          if (item.HasProperty("original_listitem_url"))
            msgItem->SetPath(item.GetProperty("original_listitem_url").asString());