Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

A few database/query optimizations #1085

Merged
merged 9 commits into from

8 participants

@Montellese
Owner

vdrfan and myself took the time to log all the SQL queries we run in XBMC (especially during startup etc) and we were surprised by the huge number of queries that are run when XBMC starts (without doing a single action as a user). We have taken a look at the queries that appeared most in the log and tracked them down. We have done the following optimizations (in the order of the commits):

  1. On every CDatabase::Open we check the version of the database we are opening to see if we need to update the database. These queries make up about 20% of all queries that are run in XBMC. Once a database has been updated, we will never have to update it again while XBMC runs so there's no need to check for it every time. Using a map we remember which databases we have already opened (and updated) and don't run the version query anymore if the db is already in the map.
  2. Adding bookmark.timeInSeconds and bookmark.totalTimeInSeconds to the video views saves us from having to make those calls to retrieve a video's resume point manually. This saves at least one query for every video when listed in the GUI.
  3. In the recently added job for recently added album songs we iterate over all retrieved songs and retrieve their album id and album thumb (two extra queries per song). The album id is already available in CMusicInfoTag (just not exposed) so we can save that query completely. Furthermore as we retreive multiple songs from the same album they can all use the same album cover so we can just remember the cover of the current album until the album changes and only then retrieve the album's cover. These two changes saved 190 (of 195) queries for the recently added album songs widget in my setup.
  4. see 5.
  5. jmarshall added a new seasons table in his recent work and that seasonid is needed to retrieve season thumbs. By storing the idSeason value in the video views and in CVideoInfoTag we can save a query for every episode. Furthermore we can save some queries in recently added episodes by also remembering the season and show thumb for every season/show and only querying the database if we haven't come across that season/show yet. This saves about half of the queries for the recently added episodes widget.
  6. the implementation for recently added albums retrieves the values for rating, year, artist and album title manually with 1 query per attribute (i.e. 4 queries per album) even though that data is already available in the CAlbum object's we get from the database.
  7. When retrieving sets, we retrieve all movies that are part of a set and put the set together based on those movies (to get additional metadata like rating, year etc). In that case we don't need to retrieve the stream details because we don't use them and they'll be retrieved when browsing into the set in the GUI. So we can save those queries.
  8. When a user adds addon shortcuts to the confluence home screen, the addon title and icon are constantly retrieved from CGUIInfoManager to be able to show them in the GUI. During that query we also check against the addon database, if the addon is disabled even though we don't use that information, so that check is unnecessary. This saves a lot of queries because they are repeated periodically as long as the user is on the home screen. This is even worse for the global search addon which has been integrated into the confluence home screen by default. For every frame (i.e. 60 times per second) we query the enabled/disabled state of the addon from the database (SYSTEM_HAS_ADDON). We haven't looked into that yet, but maybe someone can shed some light on it.
  9. When changing a view/window in the GUI we have to retrieve the next view/viewstate which includes queries to the ViewState database. Instead of doing one query to retrieve the view state we run the same query 3-4 times in different places. Especially on embedded devices these queries are rather costly and slow down the changing of views/windows. This commit is highly experimental because neither vdrfan nor myself have any real knowledge about this process.

All in all with these changes the number of queries on startup (before doing a single user interaction) goes down to 20-30%. On fast systems there's no real noteable speed-up because some of those queries are not expensive at all but on embedded devices (where I/O (i.e. accessing the sqlite database file) is more time intensive and computation power more scarce) it could speed up the startup process and some loading times of item lists.

@mkortstiege mkortstiege was assigned
@garbear
Collaborator

Off topic: Something that struck me as weird is that databases aren't loaded on startup, they're loaded "just in time." Thus, a database update isn't done on app load, it's done when the skin first uses "HasContent(Video)". Just something I found weird, and something that made debugging the DB creation/update process a little more difficult.

@theuni
Owner

nice work! can't comment on the code, though I applaud the effort.

@Montellese
Owner

OK I've pushed a few changes/fixes (as extra commits which can be squashed later on):
1. I removed the last commit about the view states as it is not correct and will take more time to look into.
2. I've added a comment in CGUIInfoManager concerning the retrieval of addon information and not checking whether the addon is disabled or not.
3. I've removed CMusicInfoTag::GetArtistId() as requested.
4. I've moved the calls to CVideoDatabase::GetStreamDetails to CVideoThumbLoader. During some of the test I ran when I re-wrote the sorting implementation I noticed that about 20-30% of the time needed to retrieve a list of movies is caused by retrieving the streamdetails for all the movies. So this might speed things up a bit. It would replace the commit about removing an unnecessary call to GetStreamDetails when retrieving movie sets.

Still open are the discussion on database updates and on the season/show thumb in recently added episodes.

@pieh
Collaborator

Could we also add some flags to item lists like "has already fetched metadata" and "has already fetched resume point" (or single flag after commit that joins bookmark table to movie/episode/musicvideo views)?

I would certainly use these flags to determine if we can return or need to fetch metadata and playcount here (the "if clause" on L364 is to determine if we already queried database): pieh@0f63058#L0L364

I could also make retrieving resume points for files mode smarter (it's not actually working in master - just in my branch). Instead of checking and quering every item as now in thumbloader, i could do single query for files+bookmarks for pathId of directory item list is representing.

I'll supply patch if that would be ok

@jmarshallnz
Owner

@pieh You could probably tap the resume stuff into the routine that grabs all playcounts for the current listing - IIRC that does a similar thing using a single query - see LoadVideoInfo()

@Montellese
Owner

@jmarshallnz I saw you comment in the thread about ShowThumb and SeasonThumb for recently added episodes and added a commit that removes those two for now. With that we can also get rid of the optimizations I came up with for that part.

That mainly leaves the database update procedure to be optimized in this PR. Should I remove that commit (because it will be fixed later on) or should I add the necessary locks around my optimizations or is there a specific plan on how to do it?

@Albinoman887

i dont know if this PR is related to my problem but as of recently i had to redo my entire media server to had to rescan my libraries (what a pain) anyways i noticed xbmc no longer grabs the codec info of the movies or tv shows automaticily anymore you have to actually play the file. I remember a bug like this a long time ago before 10.1 will this PR fix that?

@Montellese
Owner

AFAIK you don't have to play a video file you just have to view a GUI listing which contains the file and then XBMC will automatically read the streamdetails (codec, resolution, ...) of the video. AFAIK it has never been the way that XBMC grabs this information during the scanning process (don't know why though).

@Albinoman887
@jmarshallnz
Owner

@Montellese: I'd just remove season thumb - show thumb still kinda makes sense I think (balances with show fanart).

As for the db update, it's up to you - you can either protect the map with a lock or drop and we'll isolate with a proper db update thing. For a proper db update, I think we'd need to:

  1. Have a static indicating that db's were OK to open (and critical section to guard).
  2. Have a function in each db to do the update.
  3. Call said function as early as possible on app start.

It might be as simple as dividing CDatabase::Open() into two functions, one that does OpenAndUpdate() and the other that just does Open(). The latter would just check the static for whether the db is up to date and fail if not, else call Connect(currentDB, false). I think the OpenAndUpdate() would handle correctly setting up the advancedsettings and handle fallback to sqlite etc.

@Montellese
Owner

@jmarshallnz I've re-added the ShowThumb for recently added episodes (and squashed it with the commit that removed it) and I've added a lock to CDatabase::UpdateVersion()

@Montellese
Owner

So do we want to wait till someone has the time to come up with a proper fix for the database update or should I rebase & squash the commits so they can be merged?

@jmarshallnz
Owner

IMO rebase + squash and push it in.

@Montellese
Owner

OK I've rebased and squashed the commits. There were a few conflicts in RecentlyAdded.cpp (see 27e3814#commitcomment-1544120) so I'll wait till that's settled.

@Montellese
Owner

Okay I rebased again. I had to re-arrange the optimization for retrieving cover and fanart of albums in recently added album songs because the code changed from manual lookups to calling CMusicThumbLoader::LoadItem.

@jmarshallnz
Owner

If we're leaving b5b9fa8 in, then I think we mayaswell keep the season art there as well. I'm not sure whether it's worth it otherwise?

Also, abb44bf should probably be split to removing the season thumb separate (or keep it in and we can remove it later?)

@Montellese
Owner

I don't really care whether we keep the season art/thumb or not. Personally I'd always prefer to see either the tvshow thumb or the episode thumb and never the season thumb in recently added episodes but I guess that comes down to personal preferences.

@jmarshallnz
Owner

Just leave it in then and I'll kill it off later once we properly handle banners+posters?

Montellese and others added some commits
@Montellese Montellese recentlyadded: save queries for season id and season/show thumbs
Use the idSeason value available through episodeview instead of having to
retrieve it for every episode. Furthermore remember the already retrieved
season/show thumbs to save querying the same images again.
f95c66b
@Montellese Montellese recentlyadded: use values from CAlbum instead of manually querying th…
…em one by one for every album
60ba8b1
vdrfan videodb: do not retrieve streamdetails for set items - the actual str…
…eamdetails will be queried for the single items later on
30e9f45
vdrfan fixed: do not query the addon state when asking the guiinfomanager fo…
…r addon title and/or icon

This commit removes tons of useless queries made from the mainloop when using addon shortcuts on
the home screen. As the infomanager is asked for the icon or title only, it's not needed to check
whether the addon is enabled or disabled all the time.
5c10498
@Montellese Montellese move call to GetStreamDetails to CVideoThumbLoader fcb6107
@Montellese Montellese recentlyadded: remember the cover and fanart of an album
When retrieving multiple songs of the same album for recently added album
songs, remember the album's cover and fanart and therefore avoid querying
and retrieving the same cover and fanart multiple times.
ea3ea36
@Montellese
Owner

OK I re-added the SeasonThumb for recently added episodes and removed that one query for the albumid as it will never be executed anyway.

@jmarshallnz
Owner

Looks good - pull it in.

@Montellese Montellese was assigned
@Montellese
Owner

Seeing that you have started working on the real db update fix should I remove that optimization from this PR to save you a rebase?

@jmarshallnz
Owner

Doesn't worry me either way - I'm sure before it goes in I'll need to rebase anyway :)

@Montellese Montellese merged commit 35c9f14 into xbmc:master
@koying
Collaborator

Hi,

It looks that between this and some later thumb loading optimizations, the streamdetails are actually never fetched, and thus streamdetails is always NULL from JSON.

Not sure how to best solve this...

We'll probably have to manually get the stream details for all the video items that JSON-RPC wants to return to the client (but only if streamdetails are requested by the client).

Collaborator

Another solution would be to keep the "GetStreamDetails" as they were, but adding a bool to CVideoInfoTag indicating whether the details were already fetched, to avoid duplicate db fetches (trying this now)

Or do both...

The reason why I moved the call to the thumbloader is that there are several calls to GetMoviesByWhere (and therefore GetDetailsForMovie) which fetch the streamdetails (which causes an additional query and therefore additional processing time) but don't need the streamdetails. The problem isn't knowing whether the streamdetails were already retrieved or not. We want to do as few SQL queries as possible. Making the necessary calls to GetStreamDetails from JSON-RPC will not increase the number of SQL queries compared to how it worked before this commit . There will still be the same amound of SQL queries per movie but they will be triggered from a different location.

Collaborator

Re as few SQL as possible, I understand that.
I meant to do:

bool CVideoDatabase::GetStreamDetails(CVideoInfoTag& tag) const
{
  if (tag.m_iFileId < 0)
    return false;

  if (tag.m_streamDetailsLoaded)
    return tag.m_streamDetails.HasItems();

But, obviously, only retrieving stream details when requested doesn't harm either ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 6, 2012
  1. @Montellese
  2. @Montellese

    videodb: add resumeTimeInSeconds and totalTimeInSeconds to the movie/…

    Montellese authored
    …episode/musicvideo view to eliminate extra queries
  3. @Montellese
Commits on Jul 7, 2012
  1. @Montellese

    recentlyadded: save queries for season id and season/show thumbs

    Montellese authored
    Use the idSeason value available through episodeview instead of having to
    retrieve it for every episode. Furthermore remember the already retrieved
    season/show thumbs to save querying the same images again.
  2. @Montellese

    recentlyadded: use values from CAlbum instead of manually querying th…

    Montellese authored
    …em one by one for every album
  3. @Montellese

    videodb: do not retrieve streamdetails for set items - the actual str…

    vdrfan authored Montellese committed
    …eamdetails will be queried for the single items later on
  4. @Montellese

    fixed: do not query the addon state when asking the guiinfomanager fo…

    vdrfan authored Montellese committed
    …r addon title and/or icon
    
    This commit removes tons of useless queries made from the mainloop when using addon shortcuts on
    the home screen. As the infomanager is asked for the icon or title only, it's not needed to check
    whether the addon is enabled or disabled all the time.
  5. @Montellese
  6. @Montellese

    recentlyadded: remember the cover and fanart of an album

    Montellese authored
    When retrieving multiple songs of the same album for recently added album
    songs, remember the album's cover and fanart and therefore avoid querying
    and retrieving the same cover and fanart multiple times.
This page is out of date. Refresh to see the latest.
View
8 xbmc/GUIInfoManager.cpp
@@ -2824,11 +2824,15 @@ CStdString CGUIInfoManager::GetMultiInfoLabel(const GUIInfo &info, int contextWi
else if (info.m_info == SYSTEM_ADDON_TITLE ||
info.m_info == SYSTEM_ADDON_ICON)
{
+ // This logic does not check/care whether an addon has been disabled/marked as broken,
+ // it simply retrieves it's name or icon that means if an addon is placed on the home screen it
+ // will stay there even if it's disabled/marked as broken. This might need to be changed/fixed
+ // in the future.
AddonPtr addon;
if (info.GetData2() == 0)
- CAddonMgr::Get().GetAddon(const_cast<CGUIInfoManager*>(this)->GetLabel(info.GetData1(), contextWindow),addon);
+ CAddonMgr::Get().GetAddon(const_cast<CGUIInfoManager*>(this)->GetLabel(info.GetData1(), contextWindow),addon,ADDON_UNKNOWN,false);
else
- CAddonMgr::Get().GetAddon(m_stringParameters[info.GetData1()],addon);
+ CAddonMgr::Get().GetAddon(m_stringParameters[info.GetData1()],addon,ADDON_UNKNOWN,false);
if (addon && info.m_info == SYSTEM_ADDON_TITLE)
return addon->Name();
if (addon && info.m_info == SYSTEM_ADDON_ICON)
View
10 xbmc/ThumbLoader.cpp
@@ -199,12 +199,20 @@ bool CVideoThumbLoader::LoadItem(CFileItem* pItem)
m_database->Open();
// resume point
- if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_resumePoint.totalTimeInSeconds == 0)
+ if (pItem->HasVideoInfoTag() &&
+ pItem->GetVideoInfoTag()->m_resumePoint.type != CBookmark::RESUME && pItem->GetVideoInfoTag()->m_resumePoint.totalTimeInSeconds == 0)
{
if (m_database->GetResumePoint(*pItem->GetVideoInfoTag()))
pItem->SetInvalid();
}
+ if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->HasStreamDetails() &&
+ (pItem->GetVideoInfoTag()->m_type == "movie" || pItem->GetVideoInfoTag()->m_type == "episode" || pItem->GetVideoInfoTag()->m_type == "musicvideo"))
+ {
+ if (m_database->GetStreamDetails(*pItem->GetVideoInfoTag()))
+ pItem->SetInvalid();
+ }
+
// video db items normally have info in the database
if (pItem->HasVideoInfoTag() && pItem->GetArt().empty())
{
View
9 xbmc/dbwrappers/Database.cpp
@@ -31,6 +31,7 @@
#include "utils/URIUtils.h"
#include "mysqldataset.h"
#include "sqlitedataset.h"
+#include "threads/SingleLock.h"
using namespace AUTOPTR;
@@ -38,6 +39,8 @@ using namespace dbiplus;
#define MAX_COMPRESS_COUNT 20
+std::map<std::string, bool> CDatabase::m_updated;
+
CDatabase::CDatabase(void)
{
m_openCount = 0;
@@ -437,6 +440,10 @@ bool CDatabase::Connect(const DatabaseSettings &dbSettings, bool create)
bool CDatabase::UpdateVersion(const CStdString &dbName)
{
+ CSingleLock lock(m_critSect);
+ if (m_updated[dbName])
+ return true;
+
int version = 0;
m_pDS->query("SELECT idVersion FROM version\n");
if (m_pDS->num_rows() > 0)
@@ -458,6 +465,8 @@ bool CDatabase::UpdateVersion(const CStdString &dbName)
CLog::Log(LOGERROR, "Can't open the database %s as it is a NEWER version than what we were expecting?", dbName.c_str());
return false;
}
+
+ m_updated[dbName] = true;
return true;
}
View
9 xbmc/dbwrappers/Database.h
@@ -21,6 +21,10 @@
*
*/
+#include <map>
+#include <memory>
+
+#include "threads/CriticalSection.h"
#include "utils/StdString.h"
namespace dbiplus {
@@ -28,8 +32,6 @@ namespace dbiplus {
class Dataset;
}
-#include <memory>
-
class DatabaseSettings; // forward
class CDatabase
@@ -139,4 +141,7 @@ class CDatabase
bool m_bMultiWrite; /*!< True if there are any queries in the queue, false otherwise */
unsigned int m_openCount;
+
+ CCriticalSection m_critSect;
+ static std::map<std::string, bool> m_updated;
};
View
55 xbmc/utils/RecentlyAddedJob.cpp
@@ -100,7 +100,8 @@ bool CRecentlyAddedJob::UpdateVideo()
CFileItemList TVShowItems;
if (videodatabase.GetRecentlyAddedEpisodesNav("videodb://5/", TVShowItems, NUM_ITEMS))
- {
+ {
+ std::map<int, std::string> showThumbs;
for (; i < TVShowItems.Size(); ++i)
{
CFileItemPtr item = TVShowItems.Get(i);
@@ -109,7 +110,6 @@ bool CRecentlyAddedJob::UpdateVideo()
CStdString EpisodeNo;
CStdString value;
CStdString strRating;
- CStdString strSeason;
EpisodeNo.Format("s%02de%02d", EpisodeSeason, EpisodeNumber);
value.Format("%i", i + 1);
strRating.Format("%.1f", item->GetVideoInfoTag()->m_fRating);
@@ -128,9 +128,22 @@ bool CRecentlyAddedJob::UpdateVideo()
if (!item->HasThumbnail())
m_thumbLoader.LoadItem(item.get());
- int seasonID = videodatabase.GetSeasonId(item->GetVideoInfoTag()->m_iIdShow, EpisodeSeason);
- std::string seasonThumb = videodatabase.GetArtForItem(seasonID, "season", "thumb");
- std::string showThumb = videodatabase.GetArtForItem(item->GetVideoInfoTag()->m_iIdShow, "tvshow", "thumb");
+ std::string showThumb;
+ if (item->GetVideoInfoTag()->m_iIdShow > 0)
+ {
+ std::map<int, std::string>::const_iterator thumbIter;
+ if ((thumbIter = showThumbs.find(item->GetVideoInfoTag()->m_iIdShow)) != showThumbs.end())
+ showThumb = thumbIter->second;
+ else
+ {
+ showThumb = videodatabase.GetArtForItem(item->GetVideoInfoTag()->m_iIdShow, "tvshow", "thumb");
+ showThumbs[item->GetVideoInfoTag()->m_iIdShow] = showThumb;
+ }
+ }
+
+ std::string seasonThumb;
+ if (item->GetVideoInfoTag()->m_iIdSeason > 0)
+ seasonThumb = videodatabase.GetArtForItem(item->GetVideoInfoTag()->m_iIdSeason, "season", "thumb");
home->SetProperty("LatestEpisode." + value + ".Thumb" , item->GetThumbnailImage());
home->SetProperty("LatestEpisode." + value + ".ShowThumb" , showThumb);
@@ -216,9 +229,12 @@ bool CRecentlyAddedJob::UpdateMusic()
musicdatabase.Open();
if (musicdatabase.GetRecentlyAddedAlbumSongs("musicdb://", musicItems, NUM_ITEMS))
- {
+ {
+ long idAlbum = -1;
+ CStdString strAlbumThumb;
+ CStdString strAlbumFanart;
for (; i < musicItems.Size(); ++i)
- {
+ {
CFileItemPtr item = musicItems.Get(i);
CStdString value;
value.Format("%i", i + 1);
@@ -226,8 +242,19 @@ bool CRecentlyAddedJob::UpdateMusic()
CStdString strRating;
CStdString strAlbum = item->GetMusicInfoTag()->GetAlbum();
CStdString strArtist = StringUtils::Join(item->GetMusicInfoTag()->GetArtist(), g_advancedSettings.m_musicItemSeparator);
-
- loader.LoadItem(item.get());
+
+ if (idAlbum != item->GetMusicInfoTag()->GetAlbumId())
+ {
+ strAlbumThumb.clear();
+ strAlbumFanart.clear();
+ idAlbum = item->GetMusicInfoTag()->GetAlbumId();
+
+ if (loader.LoadItem(item.get()))
+ {
+ strAlbumThumb = item->GetThumbnailImage();
+ strAlbumFanart = item->GetProperty("fanart_image").asString();
+ }
+ }
strRating.Format("%c", item->GetMusicInfoTag()->GetRating());
@@ -237,8 +264,8 @@ bool CRecentlyAddedJob::UpdateMusic()
home->SetProperty("LatestSong." + value + ".Album" , strAlbum);
home->SetProperty("LatestSong." + value + ".Rating" , strRating);
home->SetProperty("LatestSong." + value + ".Path" , item->GetMusicInfoTag()->GetURL());
- home->SetProperty("LatestSong." + value + ".Thumb" , item->GetThumbnailImage());
- home->SetProperty("LatestSong." + value + ".Fanart" , item->GetProperty("fanart_image"));
+ home->SetProperty("LatestSong." + value + ".Thumb" , strAlbumThumb);
+ home->SetProperty("LatestSong." + value + ".Fanart" , strAlbumFanart);
}
}
for (; i < NUM_ITEMS; ++i)
@@ -278,10 +305,10 @@ bool CRecentlyAddedJob::UpdateMusic()
CStdString strArtist = musicdatabase.GetSingleValue("albumview", "strArtists", strSQLAlbum);
- home->SetProperty("LatestAlbum." + value + ".Title" , musicdatabase.GetAlbumById(album.idAlbum));
- home->SetProperty("LatestAlbum." + value + ".Year" , atoi(musicdatabase.GetSingleValue("album", "iYear", strSQLAlbum)));
+ home->SetProperty("LatestAlbum." + value + ".Title" , album.strAlbum);
+ home->SetProperty("LatestAlbum." + value + ".Year" , album.iYear);
home->SetProperty("LatestAlbum." + value + ".Artist" , strArtist);
- home->SetProperty("LatestAlbum." + value + ".Rating" , musicdatabase.GetSingleValue("albumview", "iRating", strSQLAlbum));
+ home->SetProperty("LatestAlbum." + value + ".Rating" , album.iRating);
home->SetProperty("LatestAlbum." + value + ".Path" , strDBpath);
home->SetProperty("LatestAlbum." + value + ".Thumb" , strThumb);
home->SetProperty("LatestAlbum." + value + ".Fanart" , strFanart);
View
44 xbmc/video/VideoDatabase.cpp
@@ -349,14 +349,21 @@ void CVideoDatabase::CreateViews()
" tvshow.c%02d AS strStudio,"
" tvshow.c%02d AS premiered,"
" tvshow.c%02d AS mpaa,"
- " tvshow.c%02d AS strShowPath "
+ " tvshow.c%02d AS strShowPath, "
+ " bookmark.timeInSeconds AS resumeTimeInSeconds, "
+ " bookmark.totalTimeInSeconds AS totalTimeInSeconds, "
+ " seasons.idSeason AS idSeason "
"FROM episode"
" JOIN files ON"
" files.idFile=episode.idFile"
" JOIN tvshow ON"
" tvshow.idShow=episode.idShow"
+ " LEFT JOIN seasons ON"
+ " seasons.idShow=episode.idShow AND seasons.season=episode.c%02d"
" JOIN path ON"
- " files.idPath=path.idPath", VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_PREMIERED, VIDEODB_ID_TV_MPAA, VIDEODB_ID_TV_BASEPATH);
+ " files.idPath=path.idPath"
+ " LEFT JOIN bookmark ON"
+ " bookmark.idFile=episode.idFile AND bookmark.type=1", VIDEODB_ID_TV_TITLE, VIDEODB_ID_TV_STUDIOS, VIDEODB_ID_TV_PREMIERED, VIDEODB_ID_TV_MPAA, VIDEODB_ID_TV_BASEPATH, VIDEODB_ID_EPISODE_SEASON);
m_pDS->exec(episodeview.c_str());
CLog::Log(LOGINFO, "create tvshowview");
@@ -388,12 +395,16 @@ void CVideoDatabase::CreateViews()
" path.strPath as strPath,"
" files.playCount as playCount,"
" files.lastPlayed as lastPlayed,"
- " files.dateAdded as dateAdded "
+ " files.dateAdded as dateAdded, "
+ " bookmark.timeInSeconds AS resumeTimeInSeconds, "
+ " bookmark.totalTimeInSeconds AS totalTimeInSeconds "
"FROM musicvideo"
" JOIN files ON"
" files.idFile=musicvideo.idFile"
" JOIN path ON"
- " path.idPath=files.idPath");
+ " path.idPath=files.idPath"
+ " LEFT JOIN bookmark ON"
+ " bookmark.idFile=musicvideo.idFile AND bookmark.type=1");
CLog::Log(LOGINFO, "create movieview");
m_pDS->exec("DROP VIEW IF EXISTS movieview");
@@ -403,12 +414,16 @@ void CVideoDatabase::CreateViews()
" path.strPath AS strPath,"
" files.playCount AS playCount,"
" files.lastPlayed AS lastPlayed, "
- " files.dateAdded AS dateAdded "
+ " files.dateAdded AS dateAdded, "
+ " bookmark.timeInSeconds AS resumeTimeInSeconds, "
+ " bookmark.totalTimeInSeconds AS totalTimeInSeconds "
"FROM movie"
" JOIN files ON"
" files.idFile=movie.idFile"
" JOIN path ON"
- " path.idPath=files.idPath");
+ " path.idPath=files.idPath"
+ " LEFT JOIN bookmark ON"
+ " bookmark.idFile=movie.idFile AND bookmark.type=1");
}
//********************************************************************************************************************************
@@ -3025,11 +3040,8 @@ CVideoInfoTag CVideoDatabase::GetDetailsForMovie(const dbiplus::sql_record* cons
GetCommonDetails(record, details);
movieTime += XbmcThreads::SystemClockMillis() - time; time = XbmcThreads::SystemClockMillis();
- GetStreamDetails(details);
-
if (needsCast)
{
- GetResumePoint(details);
GetCast("movie", "idMovie", details.m_iDbId, details.m_cast);
castTime += XbmcThreads::SystemClockMillis() - time; time = XbmcThreads::SystemClockMillis();
@@ -3130,14 +3142,16 @@ CVideoInfoTag CVideoDatabase::GetDetailsForEpisode(const dbiplus::sql_record* co
details.m_premiered.SetFromDBDate(record->at(VIDEODB_DETAILS_EPISODE_TVSHOW_AIRED).get_asString());
details.m_iIdShow = record->at(VIDEODB_DETAILS_EPISODE_TVSHOW_ID).get_asInt();
details.m_strShowPath = record->at(VIDEODB_DETAILS_EPISODE_TVSHOW_PATH).get_asString();
+ details.m_iIdSeason = record->at(VIDEODB_DETAILS_EPISODE_SEASON_ID).get_asInt();
- movieTime += XbmcThreads::SystemClockMillis() - time; time = XbmcThreads::SystemClockMillis();
+ details.m_resumePoint.timeInSeconds = record->at(VIDEODB_DETAILS_EPISODE_RESUME_TIME).get_asInt();
+ details.m_resumePoint.totalTimeInSeconds = record->at(VIDEODB_DETAILS_EPISODE_TOTAL_TIME).get_asInt();
+ details.m_resumePoint.type = CBookmark::RESUME;
- GetStreamDetails(details);
+ movieTime += XbmcThreads::SystemClockMillis() - time; time = XbmcThreads::SystemClockMillis();
if (needsCast)
{
- GetResumePoint(details);
GetCast("episode", "idEpisode", details.m_iDbId, details.m_cast);
GetCast("tvshow", "idShow", details.m_iIdShow, details.m_cast);
@@ -3170,9 +3184,6 @@ CVideoInfoTag CVideoDatabase::GetDetailsForMusicVideo(const dbiplus::sql_record*
GetCommonDetails(record, details);
movieTime += XbmcThreads::SystemClockMillis() - time; time = XbmcThreads::SystemClockMillis();
- GetStreamDetails(details);
- GetResumePoint(details);
-
details.m_strPictureURL.Parse();
return details;
}
@@ -3191,6 +3202,9 @@ void CVideoDatabase::GetCommonDetails(const dbiplus::sql_record* const record, C
details.m_playCount = record->at(VIDEODB_DETAILS_PLAYCOUNT).get_asInt();
details.m_lastPlayed.SetFromDBDateTime(record->at(VIDEODB_DETAILS_LASTPLAYED).get_asString());
details.m_dateAdded.SetFromDBDateTime(record->at(VIDEODB_DETAILS_DATEADDED).get_asString());
+ details.m_resumePoint.timeInSeconds = record->at(VIDEODB_DETAILS_RESUME_TIME).get_asInt();
+ details.m_resumePoint.totalTimeInSeconds = record->at(VIDEODB_DETAILS_TOTAL_TIME).get_asInt();
+ details.m_resumePoint.type = CBookmark::RESUME;
}
void CVideoDatabase::GetCast(const CStdString &table, const CStdString &table_id, int type_id, vector<SActorInfo> &cast)
View
9 xbmc/video/VideoDatabase.h
@@ -73,6 +73,8 @@ namespace VIDEO
#define VIDEODB_DETAILS_PLAYCOUNT VIDEODB_MAX_COLUMNS + 4
#define VIDEODB_DETAILS_LASTPLAYED VIDEODB_MAX_COLUMNS + 5
#define VIDEODB_DETAILS_DATEADDED VIDEODB_MAX_COLUMNS + 6
+#define VIDEODB_DETAILS_RESUME_TIME VIDEODB_MAX_COLUMNS + 7
+#define VIDEODB_DETAILS_TOTAL_TIME VIDEODB_MAX_COLUMNS + 8
#define VIDEODB_DETAILS_EPISODE_TVSHOW_ID VIDEODB_MAX_COLUMNS + 2
#define VIDEODB_DETAILS_EPISODE_FILE VIDEODB_MAX_COLUMNS + 3
@@ -85,6 +87,9 @@ namespace VIDEO
#define VIDEODB_DETAILS_EPISODE_TVSHOW_AIRED VIDEODB_MAX_COLUMNS + 10
#define VIDEODB_DETAILS_EPISODE_TVSHOW_MPAA VIDEODB_MAX_COLUMNS + 11
#define VIDEODB_DETAILS_EPISODE_TVSHOW_PATH VIDEODB_MAX_COLUMNS + 12
+#define VIDEODB_DETAILS_EPISODE_RESUME_TIME VIDEODB_MAX_COLUMNS + 13
+#define VIDEODB_DETAILS_EPISODE_TOTAL_TIME VIDEODB_MAX_COLUMNS + 14
+#define VIDEODB_DETAILS_EPISODE_SEASON_ID VIDEODB_MAX_COLUMNS + 15
#define VIDEODB_DETAILS_TVSHOW_PATH VIDEODB_MAX_COLUMNS + 1
#define VIDEODB_DETAILS_TVSHOW_DATEADDED VIDEODB_MAX_COLUMNS + 2
@@ -473,6 +478,7 @@ class CVideoDatabase : public CDatabase
void AddBookMarkForEpisode(const CVideoInfoTag& tag, const CBookmark& bookmark);
void DeleteBookMarkForEpisode(const CVideoInfoTag& tag);
bool GetResumePoint(CVideoInfoTag& tag);
+ bool GetStreamDetails(CVideoInfoTag& tag) const;
// scraper settings
void SetScraperForPath(const CStdString& filePath, const ADDON::ScraperPtr& info, const VIDEO::SScanSettings& settings);
@@ -751,7 +757,6 @@ class CVideoDatabase : public CDatabase
void GetDetailsFromDB(std::auto_ptr<dbiplus::Dataset> &pDS, int min, int max, const SDbTableOffsets *offsets, CVideoInfoTag &details, int idxOffset = 2);
void GetDetailsFromDB(const dbiplus::sql_record* const record, int min, int max, const SDbTableOffsets *offsets, CVideoInfoTag &details, int idxOffset = 2);
CStdString GetValueString(const CVideoInfoTag &details, int min, int max, const SDbTableOffsets *offsets) const;
- bool GetStreamDetails(CVideoInfoTag& tag) const;
private:
virtual bool CreateTables();
@@ -794,7 +799,7 @@ class CVideoDatabase : public CDatabase
*/
bool LookupByFolders(const CStdString &path, bool shows = false);
- virtual int GetMinVersion() const { return 64; };
+ virtual int GetMinVersion() const { return 66; };
virtual int GetExportVersion() const { return 1; };
const char *GetBaseDBName() const { return "MyVideos"; };
View
4 xbmc/video/VideoInfoTag.cpp
@@ -89,6 +89,7 @@ void CVideoInfoTag::Reset()
m_resumePoint.Reset();
m_resumePoint.type = CBookmark::RESUME;
m_iIdShow = -1;
+ m_iIdSeason = -1;
m_strShowPath.clear();
m_dateAdded.Reset();
m_type.clear();
@@ -329,6 +330,7 @@ void CVideoInfoTag::Archive(CArchive& ar)
ar << m_strShowPath;
ar << m_dateAdded.GetAsDBDateTime();
ar << m_type;
+ ar << m_iIdSeason;
}
else
{
@@ -407,6 +409,7 @@ void CVideoInfoTag::Archive(CArchive& ar)
ar >> dateAdded;
m_dateAdded.SetFromDBDateTime(dateAdded);
ar >> m_type;
+ ar >> m_iIdSeason;
}
}
@@ -476,6 +479,7 @@ void CVideoInfoTag::Serialize(CVariant& value)
value["tvshowpath"] = m_strShowPath;
value["dateadded"] = m_dateAdded.IsValid() ? m_dateAdded.GetAsDBDateTime() : StringUtils::EmptyString;
value["type"] = m_type;
+ value["seasonid"] = m_iIdSeason;
}
void CVideoInfoTag::ToSortable(SortItem& sortable)
View
1  xbmc/video/VideoInfoTag.h
@@ -129,6 +129,7 @@ class CVideoInfoTag : public IArchivable, public ISerializable, public ISortable
float m_fEpBookmark;
int m_iBookmarkId;
int m_iIdShow;
+ int m_iIdSeason;
CFanart m_fanart;
CStreamDetails m_streamDetails;
CBookmark m_resumePoint;
View
6 xbmc/video/dialogs/GUIDialogVideoInfo.cpp
@@ -301,8 +301,10 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
{
if (m_movieItem->GetVideoInfoTag()->m_iSeason > -1)
{
- int seasonID = db.GetSeasonId(m_movieItem->GetVideoInfoTag()->m_iIdShow,
- m_movieItem->GetVideoInfoTag()->m_iSeason);
+ int seasonID = m_movieItem->GetVideoInfoTag()->m_iIdSeason;
+ if (seasonID < 0)
+ seasonID = db.GetSeasonId(m_movieItem->GetVideoInfoTag()->m_iIdShow,
+ m_movieItem->GetVideoInfoTag()->m_iSeason);
string thumb = db.GetArtForItem(seasonID, "season", "thumb");
if (!thumb.empty())
m_movieItem->SetProperty("seasonthumb", thumb);
Something went wrong with that request. Please try again.