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
)
58 return AddAnnouncer(listener
, ANNOUNCE_ALL
);
61 void CAnnouncementManager::AddAnnouncer(IAnnouncer
* listener
, int flagMask
)
66 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
67 m_announcers
.emplace(listener
, flagMask
);
70 void CAnnouncementManager::RemoveAnnouncer(IAnnouncer
*listener
)
75 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
76 m_announcers
.erase(listener
);
79 void CAnnouncementManager::Announce(AnnouncementFlag flag
, const std::string
& message
)
82 Announce(flag
, ANNOUNCEMENT_SENDER
, message
, CFileItemPtr(), data
);
85 void CAnnouncementManager::Announce(AnnouncementFlag flag
,
86 const std::string
& message
,
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
)
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
)
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
;
138 announcement
.item
= std::make_shared
<CFileItem
>(*item
);
141 std::unique_lock
<CCriticalSection
> lock(m_queueCritSection
);
142 m_announcementQueue
.push_back(announcement
);
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()!
157 std::unordered_map
<IAnnouncer
*, int> announcers
{m_announcers
};
158 for (const auto& [announcer
, flagMask
] : announcers
)
162 announcer
->Announce(flag
, sender
, message
, data
);
167 void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag
,
168 const std::string
& sender
,
169 const std::string
& message
,
170 const std::shared_ptr
<CFileItem
>& item
,
171 const CVariant
& data
)
175 DoAnnounce(flag
, sender
, message
, data
);
179 // Extract db id of item
180 CVariant object
= data
.isNull() || data
.isObject() ? data
: CVariant::VariantTypeObject
;
184 if(item
->HasPVRChannelInfoTag())
186 const std::shared_ptr
<PVR::CPVRChannel
> channel(item
->GetPVRChannelInfoTag());
187 id
= channel
->ChannelID();
190 object
["item"]["title"] = channel
->ChannelName();
191 object
["item"]["channeltype"] = channel
->IsRadio() ? "radio" : "tv";
193 if (data
.isMember("player") && data
["player"].isMember("playerid"))
195 object
["player"]["playerid"] = channel
->IsRadio()
196 ? static_cast<int>(PLAYLIST::Id::TYPE_MUSIC
)
197 : static_cast<int>(PLAYLIST::Id::TYPE_VIDEO
);
200 else if (item
->HasVideoInfoTag() && !item
->HasPVRRecordingInfoTag())
202 id
= item
->GetVideoInfoTag()->m_iDbId
;
204 //! @todo Can be removed once this is properly handled when starting playback of a file
205 if (id
<= 0 && !item
->GetPath().empty() &&
206 (!item
->HasProperty(LOOKUP_PROPERTY
) || item
->GetProperty(LOOKUP_PROPERTY
).asBoolean()))
208 CVideoDatabase videodatabase
;
209 if (videodatabase
.Open())
211 std::string path
= item
->GetPath();
212 std::string
videoInfoTagPath(item
->GetVideoInfoTag()->m_strFileNameAndPath
);
213 if (StringUtils::StartsWith(videoInfoTagPath
, "removable://"))
214 path
= videoInfoTagPath
;
215 if (videodatabase
.LoadVideoInfo(path
, *item
->GetVideoInfoTag(), VideoDbDetailsNone
))
216 id
= item
->GetVideoInfoTag()->m_iDbId
;
218 videodatabase
.Close();
222 if (!item
->GetVideoInfoTag()->m_type
.empty())
223 type
= item
->GetVideoInfoTag()->m_type
;
225 CVideoDatabase::VideoContentTypeToString(item
->GetVideoContentType(), type
);
229 //! @todo Can be removed once this is properly handled when starting playback of a file
230 item
->SetProperty(LOOKUP_PROPERTY
, false);
232 std::string title
= item
->GetVideoInfoTag()->m_strTitle
;
234 title
= item
->GetLabel();
235 object
["item"]["title"] = title
;
237 switch (item
->GetVideoContentType())
239 case VideoDbContentType::MOVIES
:
240 if (item
->GetVideoInfoTag()->HasYear())
241 object
["item"]["year"] = item
->GetVideoInfoTag()->GetYear();
243 case VideoDbContentType::EPISODES
:
244 if (item
->GetVideoInfoTag()->m_iEpisode
>= 0)
245 object
["item"]["episode"] = item
->GetVideoInfoTag()->m_iEpisode
;
246 if (item
->GetVideoInfoTag()->m_iSeason
>= 0)
247 object
["item"]["season"] = item
->GetVideoInfoTag()->m_iSeason
;
248 if (!item
->GetVideoInfoTag()->m_strShowTitle
.empty())
249 object
["item"]["showtitle"] = item
->GetVideoInfoTag()->m_strShowTitle
;
251 case VideoDbContentType::MUSICVIDEOS
:
252 if (!item
->GetVideoInfoTag()->m_strAlbum
.empty())
253 object
["item"]["album"] = item
->GetVideoInfoTag()->m_strAlbum
;
254 if (!item
->GetVideoInfoTag()->m_artist
.empty())
255 object
["item"]["artist"] = StringUtils::Join(item
->GetVideoInfoTag()->m_artist
, " / ");
262 else if (item
->HasMusicInfoTag())
264 id
= item
->GetMusicInfoTag()->GetDatabaseId();
265 type
= MediaTypeSong
;
267 //! @todo Can be removed once this is properly handled when starting playback of a file
268 if (id
<= 0 && !item
->GetPath().empty() &&
269 (!item
->HasProperty(LOOKUP_PROPERTY
) || item
->GetProperty(LOOKUP_PROPERTY
).asBoolean()))
271 CMusicDatabase musicdatabase
;
272 if (musicdatabase
.Open())
275 if (musicdatabase
.GetSongByFileName(item
->GetPath(), song
, item
->GetStartOffset()))
277 item
->GetMusicInfoTag()->SetSong(song
);
278 id
= item
->GetMusicInfoTag()->GetDatabaseId();
281 musicdatabase
.Close();
287 //! @todo Can be removed once this is properly handled when starting playback of a file
288 item
->SetProperty(LOOKUP_PROPERTY
, false);
290 std::string title
= item
->GetMusicInfoTag()->GetTitle();
292 title
= item
->GetLabel();
293 object
["item"]["title"] = title
;
295 if (item
->GetMusicInfoTag()->GetTrackNumber() > 0)
296 object
["item"]["track"] = item
->GetMusicInfoTag()->GetTrackNumber();
297 if (!item
->GetMusicInfoTag()->GetAlbum().empty())
298 object
["item"]["album"] = item
->GetMusicInfoTag()->GetAlbum();
299 if (!item
->GetMusicInfoTag()->GetArtist().empty())
300 object
["item"]["artist"] = item
->GetMusicInfoTag()->GetArtist();
303 else if (VIDEO::IsVideo(*item
))
305 // video item but has no video info tag.
307 object
["item"]["title"] = item
->GetLabel();
309 else if (item
->HasPictureInfoTag())
312 object
["item"]["file"] = item
->GetPath();
317 object
["item"]["type"] = type
;
319 object
["item"]["id"] = id
;
321 DoAnnounce(flag
, sender
, message
, object
);
324 void CAnnouncementManager::Process()
326 SetPriority(ThreadPriority::LOWEST
);
330 std::unique_lock
<CCriticalSection
> lock(m_queueCritSection
);
331 if (!m_announcementQueue
.empty())
333 auto announcement
= m_announcementQueue
.front();
334 m_announcementQueue
.pop_front();
336 CSingleExit
ex(m_queueCritSection
);
337 DoAnnounce(announcement
.flag
, announcement
.sender
, announcement
.message
, announcement
.item
,
343 CSingleExit
ex(m_queueCritSection
);