[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / application / ApplicationStackHelper.cpp
blob515c52b5aa863d744e36fc8805c14109e6321f65
1 /*
2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "ApplicationStackHelper.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "URL.h"
14 #include "Util.h"
15 #include "cores/VideoPlayer/DVDFileInfo.h"
16 #include "filesystem/StackDirectory.h"
17 #include "utils/URIUtils.h"
18 #include "utils/log.h"
19 #include "video/VideoDatabase.h"
21 #include <utility>
23 using namespace XFILE;
25 CApplicationStackHelper::CApplicationStackHelper(void)
26 : m_currentStack(new CFileItemList)
30 void CApplicationStackHelper::Clear()
32 m_currentStackPosition = 0;
33 m_currentStack->Clear();
36 void CApplicationStackHelper::OnPlayBackStarted(const CFileItem& item)
38 std::unique_lock<CCriticalSection> lock(m_critSection);
40 // time to clean up stack map
41 if (!HasRegisteredStack(item))
42 m_stackmap.clear();
43 else
45 auto stack = GetRegisteredStack(item);
46 Stackmap::iterator itr = m_stackmap.begin();
47 while (itr != m_stackmap.end())
49 if (itr->second->m_pStack != stack)
51 itr = m_stackmap.erase(itr);
53 else
55 ++itr;
61 bool CApplicationStackHelper::InitializeStack(const CFileItem & item)
63 if (!item.IsStack())
64 return false;
66 auto stack = std::make_shared<CFileItem>(item);
68 Clear();
69 // read and determine kind of stack
70 CStackDirectory dir;
71 CURL path{item.GetDynPath()};
72 if (!dir.GetDirectory(path, *m_currentStack) || m_currentStack->IsEmpty())
73 return false;
74 for (int i = 0; i < m_currentStack->Size(); i++)
76 // keep cross-references between stack parts and the stack
77 SetRegisteredStack(GetStackPartFileItem(i), stack);
78 SetRegisteredStackPartNumber(GetStackPartFileItem(i), i);
80 m_currentStackIsDiscImageStack = URIUtils::IsDiscImageStack(item.GetDynPath());
82 return true;
85 std::optional<int64_t> CApplicationStackHelper::InitializeStackStartPartAndOffset(
86 const CFileItem& item)
88 CVideoDatabase dbs;
89 int64_t startoffset = 0;
91 // case 1: stacked ISOs
92 if (m_currentStackIsDiscImageStack)
94 // first assume values passed to the stack
95 int selectedFile = item.m_lStartPartNumber;
96 startoffset = item.GetStartOffset();
98 // check if we instructed the stack to resume from default
99 if (startoffset == STARTOFFSET_RESUME) // selected file is not specified, pick the 'last' resume point
101 if (dbs.Open())
103 CBookmark bookmark;
104 std::string path = item.GetDynPath();
105 if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
106 path = item.GetProperty("original_listitem_url").asString();
107 if (dbs.GetResumeBookMark(path, bookmark))
109 startoffset = CUtil::ConvertSecsToMilliSecs(bookmark.timeInSeconds);
110 selectedFile = bookmark.partNumber;
112 dbs.Close();
114 else
115 CLog::LogF(LOGERROR, "Cannot open VideoDatabase");
118 // make sure that the selected part is within the boundaries
119 if (selectedFile <= 0)
121 CLog::LogF(LOGWARNING, "Selected part {} out of range, playing part 1", selectedFile);
122 selectedFile = 1;
124 else if (selectedFile > m_currentStack->Size())
126 CLog::LogF(LOGWARNING, "Selected part {} out of range, playing part {}", selectedFile,
127 m_currentStack->Size());
128 selectedFile = m_currentStack->Size();
131 // set startoffset in selected item, track stack item for updating purposes, and finally play disc part
132 m_currentStackPosition = selectedFile - 1;
133 startoffset = startoffset > 0 ? STARTOFFSET_RESUME : 0;
135 // case 2: all other stacks
136 else
138 // see if we have the info in the database
139 //! @todo If user changes the time speed (FPS via framerate conversion stuff)
140 //! then these times will be wrong.
141 //! Also, this is really just a hack for the slow load up times we have
142 //! A much better solution is a fast reader of FPS and fileLength
143 //! that we can use on a file to get it's time.
144 std::vector<uint64_t> times;
145 bool haveTimes(false);
147 if (dbs.Open())
149 haveTimes = dbs.GetStackTimes(item.GetDynPath(), times);
150 dbs.Close();
153 // calculate the total time of the stack
154 uint64_t totalTimeMs = 0;
155 for (int i = 0; i < m_currentStack->Size(); i++)
157 if (haveTimes)
159 // set end time in every part
160 GetStackPartFileItem(i).SetEndOffset(times[i]);
162 else
164 int duration;
165 if (!CDVDFileInfo::GetFileDuration(GetStackPartFileItem(i).GetDynPath(), duration))
167 m_currentStack->Clear();
168 return std::nullopt;
170 totalTimeMs += duration;
171 // set end time in every part
172 GetStackPartFileItem(i).SetEndOffset(totalTimeMs);
173 times.push_back(totalTimeMs);
175 // set start time in every part
176 SetRegisteredStackPartStartTimeMs(GetStackPartFileItem(i), GetStackPartStartTimeMs(i));
178 // set total time in every part
179 totalTimeMs = GetStackTotalTimeMs();
180 for (int i = 0; i < m_currentStack->Size(); i++)
181 SetRegisteredStackTotalTimeMs(GetStackPartFileItem(i), totalTimeMs);
183 uint64_t msecs = item.GetStartOffset();
185 if (!haveTimes || item.GetStartOffset() == STARTOFFSET_RESUME)
187 if (dbs.Open())
189 // have our times now, so update the dB
190 if (!haveTimes && !times.empty())
191 dbs.SetStackTimes(item.GetDynPath(), times);
193 if (item.GetStartOffset() == STARTOFFSET_RESUME)
195 // can only resume seek here, not dvdstate
196 CBookmark bookmark;
197 std::string path = item.GetDynPath();
198 if (item.HasProperty("original_listitem_url") && URIUtils::IsPlugin(item.GetProperty("original_listitem_url").asString()))
199 path = item.GetProperty("original_listitem_url").asString();
200 if (dbs.GetResumeBookMark(path, bookmark))
201 msecs = static_cast<uint64_t>(bookmark.timeInSeconds * 1000);
202 else
203 msecs = 0;
205 dbs.Close();
209 m_currentStackPosition = GetStackPartNumberAtTimeMs(msecs);
210 startoffset = msecs - GetStackPartStartTimeMs(m_currentStackPosition);
212 return startoffset;
215 bool CApplicationStackHelper::IsPlayingISOStack() const
217 return m_currentStack->Size() > 0 && m_currentStackIsDiscImageStack;
220 bool CApplicationStackHelper::IsPlayingRegularStack() const
222 return m_currentStack->Size() > 0 && !m_currentStackIsDiscImageStack;
225 bool CApplicationStackHelper::HasNextStackPartFileItem() const
227 return m_currentStackPosition < m_currentStack->Size() - 1;
230 uint64_t CApplicationStackHelper::GetStackPartEndTimeMs(int partNumber) const
232 return GetStackPartFileItem(partNumber).GetEndOffset();
235 uint64_t CApplicationStackHelper::GetStackTotalTimeMs() const
237 return GetStackPartEndTimeMs(m_currentStack->Size() - 1);
240 int CApplicationStackHelper::GetStackPartNumberAtTimeMs(uint64_t msecs)
242 if (msecs > 0)
244 // work out where to seek to
245 for (int partNumber = 0; partNumber < m_currentStack->Size(); partNumber++)
247 if (msecs < GetStackPartEndTimeMs(partNumber))
248 return partNumber;
251 return 0;
254 void CApplicationStackHelper::ClearAllRegisteredStackInformation()
256 m_stackmap.clear();
259 std::shared_ptr<const CFileItem> CApplicationStackHelper::GetRegisteredStack(
260 const CFileItem& item) const
262 return GetStackPartInformation(item.GetDynPath())->m_pStack;
265 bool CApplicationStackHelper::HasRegisteredStack(const CFileItem& item) const
267 const auto it = m_stackmap.find(item.GetDynPath());
268 return it != m_stackmap.end() && it->second != nullptr;
271 void CApplicationStackHelper::SetRegisteredStack(const CFileItem& item,
272 std::shared_ptr<CFileItem> stackItem)
274 GetStackPartInformation(item.GetDynPath())->m_pStack = std::move(stackItem);
277 CFileItem& CApplicationStackHelper::GetStackPartFileItem(int partNumber)
279 return *(*m_currentStack)[partNumber];
282 const CFileItem& CApplicationStackHelper::GetStackPartFileItem(int partNumber) const
284 return *(*m_currentStack)[partNumber];
287 int CApplicationStackHelper::GetRegisteredStackPartNumber(const CFileItem& item)
289 return GetStackPartInformation(item.GetDynPath())->m_lStackPartNumber;
292 void CApplicationStackHelper::SetRegisteredStackPartNumber(const CFileItem& item, int partNumber)
294 GetStackPartInformation(item.GetDynPath())->m_lStackPartNumber = partNumber;
297 uint64_t CApplicationStackHelper::GetRegisteredStackPartStartTimeMs(const CFileItem& item) const
299 return GetStackPartInformation(item.GetDynPath())->m_lStackPartStartTimeMs;
302 void CApplicationStackHelper::SetRegisteredStackPartStartTimeMs(const CFileItem& item, uint64_t startTime)
304 GetStackPartInformation(item.GetDynPath())->m_lStackPartStartTimeMs = startTime;
307 uint64_t CApplicationStackHelper::GetRegisteredStackTotalTimeMs(const CFileItem& item) const
309 return GetStackPartInformation(item.GetDynPath())->m_lStackTotalTimeMs;
312 void CApplicationStackHelper::SetRegisteredStackTotalTimeMs(const CFileItem& item, uint64_t totalTime)
314 GetStackPartInformation(item.GetDynPath())->m_lStackTotalTimeMs = totalTime;
317 CApplicationStackHelper::StackPartInformationPtr CApplicationStackHelper::GetStackPartInformation(
318 const std::string& key)
320 if (m_stackmap.count(key) == 0)
322 StackPartInformationPtr value(new StackPartInformation());
323 m_stackmap[key] = value;
325 return m_stackmap[key];
328 CApplicationStackHelper::StackPartInformationPtr CApplicationStackHelper::GetStackPartInformation(
329 const std::string& key) const
331 const auto it = m_stackmap.find(key);
332 if (it == m_stackmap.end())
333 return std::make_shared<StackPartInformation>();
334 return it->second;