[FileItem][Cleanup] Add getter/setter for start/end offset
[xbmc.git] / xbmc / interfaces / AnnouncementManager.cpp
blob70a4e62c7a26f64cb221fd144870ddd22fad14d8
1 /*
2 * Copyright (C) 2005-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 "AnnouncementManager.h"
11 #include "FileItem.h"
12 #include "PlayListPlayer.h"
13 #include "music/MusicDatabase.h"
14 #include "music/tags/MusicInfoTag.h"
15 #include "pvr/channels/PVRChannel.h"
16 #include "threads/SingleLock.h"
17 #include "utils/StringUtils.h"
18 #include "utils/Variant.h"
19 #include "utils/log.h"
20 #include "video/VideoDatabase.h"
22 #include <mutex>
23 #include <stdio.h>
25 #define LOOKUP_PROPERTY "database-lookup"
27 using namespace ANNOUNCEMENT;
29 const std::string CAnnouncementManager::ANNOUNCEMENT_SENDER = "xbmc";
31 CAnnouncementManager::CAnnouncementManager() : CThread("Announce")
35 CAnnouncementManager::~CAnnouncementManager()
37 Deinitialize();
40 void CAnnouncementManager::Start()
42 Create();
45 void CAnnouncementManager::Deinitialize()
47 m_bStop = true;
48 m_queueEvent.Set();
49 StopThread();
50 std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
51 m_announcers.clear();
54 void CAnnouncementManager::AddAnnouncer(IAnnouncer *listener)
56 if (!listener)
57 return;
59 std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
60 m_announcers.push_back(listener);
63 void CAnnouncementManager::RemoveAnnouncer(IAnnouncer *listener)
65 if (!listener)
66 return;
68 std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
69 for (unsigned int i = 0; i < m_announcers.size(); i++)
71 if (m_announcers[i] == listener)
73 m_announcers.erase(m_announcers.begin() + i);
74 return;
79 void CAnnouncementManager::Announce(AnnouncementFlag flag, const std::string& message)
81 CVariant data;
82 Announce(flag, ANNOUNCEMENT_SENDER, message, CFileItemPtr(), data);
85 void CAnnouncementManager::Announce(AnnouncementFlag flag,
86 const std::string& message,
87 const CVariant& data)
89 Announce(flag, ANNOUNCEMENT_SENDER, message, CFileItemPtr(), data);
92 void CAnnouncementManager::Announce(AnnouncementFlag flag,
93 const std::string& message,
94 const std::shared_ptr<const CFileItem>& item)
96 CVariant data;
97 Announce(flag, ANNOUNCEMENT_SENDER, message, item, data);
100 void CAnnouncementManager::Announce(AnnouncementFlag flag,
101 const std::string& message,
102 const std::shared_ptr<const CFileItem>& item,
103 const CVariant& data)
105 Announce(flag, ANNOUNCEMENT_SENDER, message, item, data);
109 void CAnnouncementManager::Announce(AnnouncementFlag flag,
110 const std::string& sender,
111 const std::string& message)
113 CVariant data;
114 Announce(flag, sender, message, CFileItemPtr(), data);
117 void CAnnouncementManager::Announce(AnnouncementFlag flag,
118 const std::string& sender,
119 const std::string& message,
120 const CVariant& data)
122 Announce(flag, sender, message, CFileItemPtr(), data);
125 void CAnnouncementManager::Announce(AnnouncementFlag flag,
126 const std::string& sender,
127 const std::string& message,
128 const std::shared_ptr<const CFileItem>& item,
129 const CVariant& data)
131 CAnnounceData announcement;
132 announcement.flag = flag;
133 announcement.sender = sender;
134 announcement.message = message;
135 announcement.data = data;
137 if (item != nullptr)
138 announcement.item = CFileItemPtr(new CFileItem(*item));
141 std::unique_lock<CCriticalSection> lock(m_queueCritSection);
142 m_announcementQueue.push_back(announcement);
144 m_queueEvent.Set();
147 void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag,
148 const std::string& sender,
149 const std::string& message,
150 const CVariant& data)
152 CLog::Log(LOGDEBUG, LOGANNOUNCE, "CAnnouncementManager - Announcement: {} from {}", message, sender);
154 std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
156 // Make a copy of announcers. They may be removed or even remove themselves during execution of IAnnouncer::Announce()!
158 std::vector<IAnnouncer *> announcers(m_announcers);
159 for (unsigned int i = 0; i < announcers.size(); i++)
160 announcers[i]->Announce(flag, sender, message, data);
163 void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag,
164 const std::string& sender,
165 const std::string& message,
166 const CFileItemPtr& item,
167 const CVariant& data)
169 if (item == nullptr)
171 DoAnnounce(flag, sender, message, data);
172 return;
175 // Extract db id of item
176 CVariant object = data.isNull() || data.isObject() ? data : CVariant::VariantTypeObject;
177 std::string type;
178 int id = 0;
180 if(item->HasPVRChannelInfoTag())
182 const std::shared_ptr<PVR::CPVRChannel> channel(item->GetPVRChannelInfoTag());
183 id = channel->ChannelID();
184 type = "channel";
186 object["item"]["title"] = channel->ChannelName();
187 object["item"]["channeltype"] = channel->IsRadio() ? "radio" : "tv";
189 if (data.isMember("player") && data["player"].isMember("playerid"))
190 object["player"]["playerid"] = channel->IsRadio() ? PLAYLIST_MUSIC : PLAYLIST_VIDEO;
192 else if (item->HasVideoInfoTag() && !item->HasPVRRecordingInfoTag())
194 id = item->GetVideoInfoTag()->m_iDbId;
196 //! @todo Can be removed once this is properly handled when starting playback of a file
197 if (id <= 0 && !item->GetPath().empty() &&
198 (!item->HasProperty(LOOKUP_PROPERTY) || item->GetProperty(LOOKUP_PROPERTY).asBoolean()))
200 CVideoDatabase videodatabase;
201 if (videodatabase.Open())
203 std::string path = item->GetPath();
204 std::string videoInfoTagPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
205 if (StringUtils::StartsWith(videoInfoTagPath, "removable://"))
206 path = videoInfoTagPath;
207 if (videodatabase.LoadVideoInfo(path, *item->GetVideoInfoTag(), VideoDbDetailsNone))
208 id = item->GetVideoInfoTag()->m_iDbId;
210 videodatabase.Close();
214 if (!item->GetVideoInfoTag()->m_type.empty())
215 type = item->GetVideoInfoTag()->m_type;
216 else
217 CVideoDatabase::VideoContentTypeToString((VIDEODB_CONTENT_TYPE)item->GetVideoContentType(), type);
219 if (id <= 0)
221 //! @todo Can be removed once this is properly handled when starting playback of a file
222 item->SetProperty(LOOKUP_PROPERTY, false);
224 std::string title = item->GetVideoInfoTag()->m_strTitle;
225 if (title.empty())
226 title = item->GetLabel();
227 object["item"]["title"] = title;
229 switch (item->GetVideoContentType())
231 case VIDEODB_CONTENT_MOVIES:
232 if (item->GetVideoInfoTag()->HasYear())
233 object["item"]["year"] = item->GetVideoInfoTag()->GetYear();
234 break;
235 case VIDEODB_CONTENT_EPISODES:
236 if (item->GetVideoInfoTag()->m_iEpisode >= 0)
237 object["item"]["episode"] = item->GetVideoInfoTag()->m_iEpisode;
238 if (item->GetVideoInfoTag()->m_iSeason >= 0)
239 object["item"]["season"] = item->GetVideoInfoTag()->m_iSeason;
240 if (!item->GetVideoInfoTag()->m_strShowTitle.empty())
241 object["item"]["showtitle"] = item->GetVideoInfoTag()->m_strShowTitle;
242 break;
243 case VIDEODB_CONTENT_MUSICVIDEOS:
244 if (!item->GetVideoInfoTag()->m_strAlbum.empty())
245 object["item"]["album"] = item->GetVideoInfoTag()->m_strAlbum;
246 if (!item->GetVideoInfoTag()->m_artist.empty())
247 object["item"]["artist"] = StringUtils::Join(item->GetVideoInfoTag()->m_artist, " / ");
248 break;
252 else if (item->HasMusicInfoTag())
254 id = item->GetMusicInfoTag()->GetDatabaseId();
255 type = MediaTypeSong;
257 //! @todo Can be removed once this is properly handled when starting playback of a file
258 if (id <= 0 && !item->GetPath().empty() &&
259 (!item->HasProperty(LOOKUP_PROPERTY) || item->GetProperty(LOOKUP_PROPERTY).asBoolean()))
261 CMusicDatabase musicdatabase;
262 if (musicdatabase.Open())
264 CSong song;
265 if (musicdatabase.GetSongByFileName(item->GetPath(), song, item->GetStartOffset()))
267 item->GetMusicInfoTag()->SetSong(song);
268 id = item->GetMusicInfoTag()->GetDatabaseId();
271 musicdatabase.Close();
275 if (id <= 0)
277 //! @todo Can be removed once this is properly handled when starting playback of a file
278 item->SetProperty(LOOKUP_PROPERTY, false);
280 std::string title = item->GetMusicInfoTag()->GetTitle();
281 if (title.empty())
282 title = item->GetLabel();
283 object["item"]["title"] = title;
285 if (item->GetMusicInfoTag()->GetTrackNumber() > 0)
286 object["item"]["track"] = item->GetMusicInfoTag()->GetTrackNumber();
287 if (!item->GetMusicInfoTag()->GetAlbum().empty())
288 object["item"]["album"] = item->GetMusicInfoTag()->GetAlbum();
289 if (!item->GetMusicInfoTag()->GetArtist().empty())
290 object["item"]["artist"] = item->GetMusicInfoTag()->GetArtist();
293 else if (item->IsVideo())
295 // video item but has no video info tag.
296 type = "movie";
297 object["item"]["title"] = item->GetLabel();
299 else if (item->HasPictureInfoTag())
301 type = "picture";
302 object["item"]["file"] = item->GetPath();
304 else
305 type = "unknown";
307 object["item"]["type"] = type;
308 if (id > 0)
309 object["item"]["id"] = id;
311 DoAnnounce(flag, sender, message, object);
314 void CAnnouncementManager::Process()
316 SetPriority(ThreadPriority::LOWEST);
318 while (!m_bStop)
320 std::unique_lock<CCriticalSection> lock(m_queueCritSection);
321 if (!m_announcementQueue.empty())
323 auto announcement = m_announcementQueue.front();
324 m_announcementQueue.pop_front();
326 CSingleExit ex(m_queueCritSection);
327 DoAnnounce(announcement.flag, announcement.sender, announcement.message, announcement.item,
328 announcement.data);
331 else
333 CSingleExit ex(m_queueCritSection);
334 m_queueEvent.Wait();