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 "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"
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()
40 void CAnnouncementManager::Start()
45 void CAnnouncementManager::Deinitialize()
50 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
54 void CAnnouncementManager::AddAnnouncer(IAnnouncer
*listener
)
59 std::unique_lock
<CCriticalSection
> lock(m_announcersCritSection
);
60 m_announcers
.push_back(listener
);
63 void CAnnouncementManager::RemoveAnnouncer(IAnnouncer
*listener
)
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
);
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
= CFileItemPtr(new 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()!
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
)
171 DoAnnounce(flag
, sender
, message
, data
);
175 // Extract db id of item
176 CVariant object
= data
.isNull() || data
.isObject() ? data
: CVariant::VariantTypeObject
;
180 if(item
->HasPVRChannelInfoTag())
182 const std::shared_ptr
<PVR::CPVRChannel
> channel(item
->GetPVRChannelInfoTag());
183 id
= channel
->ChannelID();
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
;
217 CVideoDatabase::VideoContentTypeToString((VIDEODB_CONTENT_TYPE
)item
->GetVideoContentType(), type
);
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
;
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();
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
;
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
, " / ");
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())
265 if (musicdatabase
.GetSongByFileName(item
->GetPath(), song
, item
->GetStartOffset()))
267 item
->GetMusicInfoTag()->SetSong(song
);
268 id
= item
->GetMusicInfoTag()->GetDatabaseId();
271 musicdatabase
.Close();
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();
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.
297 object
["item"]["title"] = item
->GetLabel();
299 else if (item
->HasPictureInfoTag())
302 object
["item"]["file"] = item
->GetPath();
307 object
["item"]["type"] = type
;
309 object
["item"]["id"] = id
;
311 DoAnnounce(flag
, sender
, message
, object
);
314 void CAnnouncementManager::Process()
316 SetPriority(ThreadPriority::LOWEST
);
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
,
333 CSingleExit
ex(m_queueCritSection
);