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.
9 #include "AnnouncementManager.h"
12 #include "music/MusicDatabase.h"
13 #include "music/tags/MusicInfoTag.h"
14 #include "playlists/PlayListTypes.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"
21 #include "video/VideoFileItemClassify.h"
26 #define LOOKUP_PROPERTY "database-lookup"
28 using namespace ANNOUNCEMENT
;
31 const std::string
CAnnouncementManager::ANNOUNCEMENT_SENDER
= "xbmc";
33 CAnnouncementManager::CAnnouncementManager() : CThread("Announce")
37 CAnnouncementManager::~CAnnouncementManager()
42 void CAnnouncementManager::Start()
47 void CAnnouncementManager::Deinitialize()
52 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
56 void CAnnouncementManager::AddAnnouncer(IAnnouncer
*listener
)
61 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
62 m_announcers
.push_back(listener
);
65 void CAnnouncementManager::RemoveAnnouncer(IAnnouncer
*listener
)
70 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
71 for (unsigned int i
= 0; i
< m_announcers
.size(); i
++)
73 if (m_announcers
[i
] == listener
)
75 m_announcers
.erase(m_announcers
.begin() + i
);
81 void CAnnouncementManager::Announce(AnnouncementFlag flag
, const std::string
& message
)
84 Announce(flag
, ANNOUNCEMENT_SENDER
, message
, CFileItemPtr(), data
);
87 void CAnnouncementManager::Announce(AnnouncementFlag flag
,
88 const std::string
& message
,
91 Announce(flag
, ANNOUNCEMENT_SENDER
, message
, CFileItemPtr(), data
);
94 void CAnnouncementManager::Announce(AnnouncementFlag flag
,
95 const std::string
& message
,
96 const std::shared_ptr
<const CFileItem
>& item
)
99 Announce(flag
, ANNOUNCEMENT_SENDER
, message
, item
, data
);
102 void CAnnouncementManager::Announce(AnnouncementFlag flag
,
103 const std::string
& message
,
104 const std::shared_ptr
<const CFileItem
>& item
,
105 const CVariant
& data
)
107 Announce(flag
, ANNOUNCEMENT_SENDER
, message
, item
, data
);
111 void CAnnouncementManager::Announce(AnnouncementFlag flag
,
112 const std::string
& sender
,
113 const std::string
& message
)
116 Announce(flag
, sender
, message
, CFileItemPtr(), data
);
119 void CAnnouncementManager::Announce(AnnouncementFlag flag
,
120 const std::string
& sender
,
121 const std::string
& message
,
122 const CVariant
& data
)
124 Announce(flag
, sender
, message
, CFileItemPtr(), data
);
127 void CAnnouncementManager::Announce(AnnouncementFlag flag
,
128 const std::string
& sender
,
129 const std::string
& message
,
130 const std::shared_ptr
<const CFileItem
>& item
,
131 const CVariant
& data
)
133 CAnnounceData announcement
;
134 announcement
.flag
= flag
;
135 announcement
.sender
= sender
;
136 announcement
.message
= message
;
137 announcement
.data
= data
;
140 announcement
.item
= std::make_shared
<CFileItem
>(*item
);
143 std::unique_lock
<CCriticalSection
> lock(m_queueCritSection
);
144 m_announcementQueue
.push_back(announcement
);
149 void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag
,
150 const std::string
& sender
,
151 const std::string
& message
,
152 const CVariant
& data
)
154 CLog::Log(LOGDEBUG
, LOGANNOUNCE
, "CAnnouncementManager - Announcement: {} from {}", message
, sender
);
156 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
158 // Make a copy of announcers. They may be removed or even remove themselves during execution of IAnnouncer::Announce()!
160 std::vector
<IAnnouncer
*> announcers(m_announcers
);
161 for (unsigned int i
= 0; i
< announcers
.size(); i
++)
162 announcers
[i
]->Announce(flag
, sender
, message
, data
);
165 void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag
,
166 const std::string
& sender
,
167 const std::string
& message
,
168 const std::shared_ptr
<CFileItem
>& item
,
169 const CVariant
& data
)
173 DoAnnounce(flag
, sender
, message
, data
);
177 // Extract db id of item
178 CVariant object
= data
.isNull() || data
.isObject() ? data
: CVariant::VariantTypeObject
;
182 if(item
->HasPVRChannelInfoTag())
184 const std::shared_ptr
<PVR::CPVRChannel
> channel(item
->GetPVRChannelInfoTag());
185 id
= channel
->ChannelID();
188 object
["item"]["title"] = channel
->ChannelName();
189 object
["item"]["channeltype"] = channel
->IsRadio() ? "radio" : "tv";
191 if (data
.isMember("player") && data
["player"].isMember("playerid"))
193 object
["player"]["playerid"] = channel
->IsRadio()
194 ? static_cast<int>(PLAYLIST::Id::TYPE_MUSIC
)
195 : static_cast<int>(PLAYLIST::Id::TYPE_VIDEO
);
198 else if (item
->HasVideoInfoTag() && !item
->HasPVRRecordingInfoTag())
200 id
= item
->GetVideoInfoTag()->m_iDbId
;
202 //! @todo Can be removed once this is properly handled when starting playback of a file
203 if (id
<= 0 && !item
->GetPath().empty() &&
204 (!item
->HasProperty(LOOKUP_PROPERTY
) || item
->GetProperty(LOOKUP_PROPERTY
).asBoolean()))
206 CVideoDatabase videodatabase
;
207 if (videodatabase
.Open())
209 std::string path
= item
->GetPath();
210 std::string
videoInfoTagPath(item
->GetVideoInfoTag()->m_strFileNameAndPath
);
211 if (StringUtils::StartsWith(videoInfoTagPath
, "removable://"))
212 path
= videoInfoTagPath
;
213 if (videodatabase
.LoadVideoInfo(path
, *item
->GetVideoInfoTag(), VideoDbDetailsNone
))
214 id
= item
->GetVideoInfoTag()->m_iDbId
;
216 videodatabase
.Close();
220 if (!item
->GetVideoInfoTag()->m_type
.empty())
221 type
= item
->GetVideoInfoTag()->m_type
;
223 CVideoDatabase::VideoContentTypeToString(item
->GetVideoContentType(), type
);
227 //! @todo Can be removed once this is properly handled when starting playback of a file
228 item
->SetProperty(LOOKUP_PROPERTY
, false);
230 std::string title
= item
->GetVideoInfoTag()->m_strTitle
;
232 title
= item
->GetLabel();
233 object
["item"]["title"] = title
;
235 switch (item
->GetVideoContentType())
237 case VideoDbContentType::MOVIES
:
238 if (item
->GetVideoInfoTag()->HasYear())
239 object
["item"]["year"] = item
->GetVideoInfoTag()->GetYear();
241 case VideoDbContentType::EPISODES
:
242 if (item
->GetVideoInfoTag()->m_iEpisode
>= 0)
243 object
["item"]["episode"] = item
->GetVideoInfoTag()->m_iEpisode
;
244 if (item
->GetVideoInfoTag()->m_iSeason
>= 0)
245 object
["item"]["season"] = item
->GetVideoInfoTag()->m_iSeason
;
246 if (!item
->GetVideoInfoTag()->m_strShowTitle
.empty())
247 object
["item"]["showtitle"] = item
->GetVideoInfoTag()->m_strShowTitle
;
249 case VideoDbContentType::MUSICVIDEOS
:
250 if (!item
->GetVideoInfoTag()->m_strAlbum
.empty())
251 object
["item"]["album"] = item
->GetVideoInfoTag()->m_strAlbum
;
252 if (!item
->GetVideoInfoTag()->m_artist
.empty())
253 object
["item"]["artist"] = StringUtils::Join(item
->GetVideoInfoTag()->m_artist
, " / ");
260 else if (item
->HasMusicInfoTag())
262 id
= item
->GetMusicInfoTag()->GetDatabaseId();
263 type
= MediaTypeSong
;
265 //! @todo Can be removed once this is properly handled when starting playback of a file
266 if (id
<= 0 && !item
->GetPath().empty() &&
267 (!item
->HasProperty(LOOKUP_PROPERTY
) || item
->GetProperty(LOOKUP_PROPERTY
).asBoolean()))
269 CMusicDatabase musicdatabase
;
270 if (musicdatabase
.Open())
273 if (musicdatabase
.GetSongByFileName(item
->GetPath(), song
, item
->GetStartOffset()))
275 item
->GetMusicInfoTag()->SetSong(song
);
276 id
= item
->GetMusicInfoTag()->GetDatabaseId();
279 musicdatabase
.Close();
285 //! @todo Can be removed once this is properly handled when starting playback of a file
286 item
->SetProperty(LOOKUP_PROPERTY
, false);
288 std::string title
= item
->GetMusicInfoTag()->GetTitle();
290 title
= item
->GetLabel();
291 object
["item"]["title"] = title
;
293 if (item
->GetMusicInfoTag()->GetTrackNumber() > 0)
294 object
["item"]["track"] = item
->GetMusicInfoTag()->GetTrackNumber();
295 if (!item
->GetMusicInfoTag()->GetAlbum().empty())
296 object
["item"]["album"] = item
->GetMusicInfoTag()->GetAlbum();
297 if (!item
->GetMusicInfoTag()->GetArtist().empty())
298 object
["item"]["artist"] = item
->GetMusicInfoTag()->GetArtist();
301 else if (VIDEO::IsVideo(*item
))
303 // video item but has no video info tag.
305 object
["item"]["title"] = item
->GetLabel();
307 else if (item
->HasPictureInfoTag())
310 object
["item"]["file"] = item
->GetPath();
315 object
["item"]["type"] = type
;
317 object
["item"]["id"] = id
;
319 DoAnnounce(flag
, sender
, message
, object
);
322 void CAnnouncementManager::Process()
324 SetPriority(ThreadPriority::LOWEST
);
328 std::unique_lock
<CCriticalSection
> lock(m_queueCritSection
);
329 if (!m_announcementQueue
.empty())
331 auto announcement
= m_announcementQueue
.front();
332 m_announcementQueue
.pop_front();
334 CSingleExit
ex(m_queueCritSection
);
335 DoAnnounce(announcement
.flag
, announcement
.sender
, announcement
.message
, announcement
.item
,
341 CSingleExit
ex(m_queueCritSection
);