summaryrefslogtreecommitdiffstats
path: root/xbmc/interfaces/AnnouncementManager.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /xbmc/interfaces/AnnouncementManager.cpp
parentInitial commit. (diff)
downloadkodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz
kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/interfaces/AnnouncementManager.cpp')
-rw-r--r--xbmc/interfaces/AnnouncementManager.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/xbmc/interfaces/AnnouncementManager.cpp b/xbmc/interfaces/AnnouncementManager.cpp
new file mode 100644
index 0000000..2f5101b
--- /dev/null
+++ b/xbmc/interfaces/AnnouncementManager.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "AnnouncementManager.h"
+
+#include "FileItem.h"
+#include "music/MusicDatabase.h"
+#include "music/tags/MusicInfoTag.h"
+#include "playlists/PlayListTypes.h"
+#include "pvr/channels/PVRChannel.h"
+#include "threads/SingleLock.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+#include "video/VideoDatabase.h"
+
+#include <mutex>
+#include <stdio.h>
+
+#define LOOKUP_PROPERTY "database-lookup"
+
+using namespace ANNOUNCEMENT;
+
+const std::string CAnnouncementManager::ANNOUNCEMENT_SENDER = "xbmc";
+
+CAnnouncementManager::CAnnouncementManager() : CThread("Announce")
+{
+}
+
+CAnnouncementManager::~CAnnouncementManager()
+{
+ Deinitialize();
+}
+
+void CAnnouncementManager::Start()
+{
+ Create();
+}
+
+void CAnnouncementManager::Deinitialize()
+{
+ m_bStop = true;
+ m_queueEvent.Set();
+ StopThread();
+ std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
+ m_announcers.clear();
+}
+
+void CAnnouncementManager::AddAnnouncer(IAnnouncer *listener)
+{
+ if (!listener)
+ return;
+
+ std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
+ m_announcers.push_back(listener);
+}
+
+void CAnnouncementManager::RemoveAnnouncer(IAnnouncer *listener)
+{
+ if (!listener)
+ return;
+
+ std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
+ for (unsigned int i = 0; i < m_announcers.size(); i++)
+ {
+ if (m_announcers[i] == listener)
+ {
+ m_announcers.erase(m_announcers.begin() + i);
+ return;
+ }
+ }
+}
+
+void CAnnouncementManager::Announce(AnnouncementFlag flag, const std::string& message)
+{
+ CVariant data;
+ Announce(flag, ANNOUNCEMENT_SENDER, message, CFileItemPtr(), data);
+}
+
+void CAnnouncementManager::Announce(AnnouncementFlag flag,
+ const std::string& message,
+ const CVariant& data)
+{
+ Announce(flag, ANNOUNCEMENT_SENDER, message, CFileItemPtr(), data);
+}
+
+void CAnnouncementManager::Announce(AnnouncementFlag flag,
+ const std::string& message,
+ const std::shared_ptr<const CFileItem>& item)
+{
+ CVariant data;
+ Announce(flag, ANNOUNCEMENT_SENDER, message, item, data);
+}
+
+void CAnnouncementManager::Announce(AnnouncementFlag flag,
+ const std::string& message,
+ const std::shared_ptr<const CFileItem>& item,
+ const CVariant& data)
+{
+ Announce(flag, ANNOUNCEMENT_SENDER, message, item, data);
+}
+
+
+void CAnnouncementManager::Announce(AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message)
+{
+ CVariant data;
+ Announce(flag, sender, message, CFileItemPtr(), data);
+}
+
+void CAnnouncementManager::Announce(AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const CVariant& data)
+{
+ Announce(flag, sender, message, CFileItemPtr(), data);
+}
+
+void CAnnouncementManager::Announce(AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const std::shared_ptr<const CFileItem>& item,
+ const CVariant& data)
+{
+ CAnnounceData announcement;
+ announcement.flag = flag;
+ announcement.sender = sender;
+ announcement.message = message;
+ announcement.data = data;
+
+ if (item != nullptr)
+ announcement.item = CFileItemPtr(new CFileItem(*item));
+
+ {
+ std::unique_lock<CCriticalSection> lock(m_queueCritSection);
+ m_announcementQueue.push_back(announcement);
+ }
+ m_queueEvent.Set();
+}
+
+void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const CVariant& data)
+{
+ CLog::Log(LOGDEBUG, LOGANNOUNCE, "CAnnouncementManager - Announcement: {} from {}", message, sender);
+
+ std::unique_lock<CCriticalSection> lock(m_announcersCritSection);
+
+ // Make a copy of announcers. They may be removed or even remove themselves during execution of IAnnouncer::Announce()!
+
+ std::vector<IAnnouncer *> announcers(m_announcers);
+ for (unsigned int i = 0; i < announcers.size(); i++)
+ announcers[i]->Announce(flag, sender, message, data);
+}
+
+void CAnnouncementManager::DoAnnounce(AnnouncementFlag flag,
+ const std::string& sender,
+ const std::string& message,
+ const std::shared_ptr<CFileItem>& item,
+ const CVariant& data)
+{
+ if (item == nullptr)
+ {
+ DoAnnounce(flag, sender, message, data);
+ return;
+ }
+
+ // Extract db id of item
+ CVariant object = data.isNull() || data.isObject() ? data : CVariant::VariantTypeObject;
+ std::string type;
+ int id = 0;
+
+ if(item->HasPVRChannelInfoTag())
+ {
+ const std::shared_ptr<PVR::CPVRChannel> channel(item->GetPVRChannelInfoTag());
+ id = channel->ChannelID();
+ type = "channel";
+
+ object["item"]["title"] = channel->ChannelName();
+ object["item"]["channeltype"] = channel->IsRadio() ? "radio" : "tv";
+
+ if (data.isMember("player") && data["player"].isMember("playerid"))
+ {
+ object["player"]["playerid"] =
+ channel->IsRadio() ? PLAYLIST::TYPE_MUSIC : PLAYLIST::TYPE_VIDEO;
+ }
+ }
+ else if (item->HasVideoInfoTag() && !item->HasPVRRecordingInfoTag())
+ {
+ id = item->GetVideoInfoTag()->m_iDbId;
+
+ //! @todo Can be removed once this is properly handled when starting playback of a file
+ if (id <= 0 && !item->GetPath().empty() &&
+ (!item->HasProperty(LOOKUP_PROPERTY) || item->GetProperty(LOOKUP_PROPERTY).asBoolean()))
+ {
+ CVideoDatabase videodatabase;
+ if (videodatabase.Open())
+ {
+ std::string path = item->GetPath();
+ std::string videoInfoTagPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
+ if (StringUtils::StartsWith(videoInfoTagPath, "removable://"))
+ path = videoInfoTagPath;
+ if (videodatabase.LoadVideoInfo(path, *item->GetVideoInfoTag(), VideoDbDetailsNone))
+ id = item->GetVideoInfoTag()->m_iDbId;
+
+ videodatabase.Close();
+ }
+ }
+
+ if (!item->GetVideoInfoTag()->m_type.empty())
+ type = item->GetVideoInfoTag()->m_type;
+ else
+ CVideoDatabase::VideoContentTypeToString(item->GetVideoContentType(), type);
+
+ if (id <= 0)
+ {
+ //! @todo Can be removed once this is properly handled when starting playback of a file
+ item->SetProperty(LOOKUP_PROPERTY, false);
+
+ std::string title = item->GetVideoInfoTag()->m_strTitle;
+ if (title.empty())
+ title = item->GetLabel();
+ object["item"]["title"] = title;
+
+ switch (item->GetVideoContentType())
+ {
+ case VideoDbContentType::MOVIES:
+ if (item->GetVideoInfoTag()->HasYear())
+ object["item"]["year"] = item->GetVideoInfoTag()->GetYear();
+ break;
+ case VideoDbContentType::EPISODES:
+ if (item->GetVideoInfoTag()->m_iEpisode >= 0)
+ object["item"]["episode"] = item->GetVideoInfoTag()->m_iEpisode;
+ if (item->GetVideoInfoTag()->m_iSeason >= 0)
+ object["item"]["season"] = item->GetVideoInfoTag()->m_iSeason;
+ if (!item->GetVideoInfoTag()->m_strShowTitle.empty())
+ object["item"]["showtitle"] = item->GetVideoInfoTag()->m_strShowTitle;
+ break;
+ case VideoDbContentType::MUSICVIDEOS:
+ if (!item->GetVideoInfoTag()->m_strAlbum.empty())
+ object["item"]["album"] = item->GetVideoInfoTag()->m_strAlbum;
+ if (!item->GetVideoInfoTag()->m_artist.empty())
+ object["item"]["artist"] = StringUtils::Join(item->GetVideoInfoTag()->m_artist, " / ");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else if (item->HasMusicInfoTag())
+ {
+ id = item->GetMusicInfoTag()->GetDatabaseId();
+ type = MediaTypeSong;
+
+ //! @todo Can be removed once this is properly handled when starting playback of a file
+ if (id <= 0 && !item->GetPath().empty() &&
+ (!item->HasProperty(LOOKUP_PROPERTY) || item->GetProperty(LOOKUP_PROPERTY).asBoolean()))
+ {
+ CMusicDatabase musicdatabase;
+ if (musicdatabase.Open())
+ {
+ CSong song;
+ if (musicdatabase.GetSongByFileName(item->GetPath(), song, item->GetStartOffset()))
+ {
+ item->GetMusicInfoTag()->SetSong(song);
+ id = item->GetMusicInfoTag()->GetDatabaseId();
+ }
+
+ musicdatabase.Close();
+ }
+ }
+
+ if (id <= 0)
+ {
+ //! @todo Can be removed once this is properly handled when starting playback of a file
+ item->SetProperty(LOOKUP_PROPERTY, false);
+
+ std::string title = item->GetMusicInfoTag()->GetTitle();
+ if (title.empty())
+ title = item->GetLabel();
+ object["item"]["title"] = title;
+
+ if (item->GetMusicInfoTag()->GetTrackNumber() > 0)
+ object["item"]["track"] = item->GetMusicInfoTag()->GetTrackNumber();
+ if (!item->GetMusicInfoTag()->GetAlbum().empty())
+ object["item"]["album"] = item->GetMusicInfoTag()->GetAlbum();
+ if (!item->GetMusicInfoTag()->GetArtist().empty())
+ object["item"]["artist"] = item->GetMusicInfoTag()->GetArtist();
+ }
+ }
+ else if (item->IsVideo())
+ {
+ // video item but has no video info tag.
+ type = "movie";
+ object["item"]["title"] = item->GetLabel();
+ }
+ else if (item->HasPictureInfoTag())
+ {
+ type = "picture";
+ object["item"]["file"] = item->GetPath();
+ }
+ else
+ type = "unknown";
+
+ object["item"]["type"] = type;
+ if (id > 0)
+ object["item"]["id"] = id;
+
+ DoAnnounce(flag, sender, message, object);
+}
+
+void CAnnouncementManager::Process()
+{
+ SetPriority(ThreadPriority::LOWEST);
+
+ while (!m_bStop)
+ {
+ std::unique_lock<CCriticalSection> lock(m_queueCritSection);
+ if (!m_announcementQueue.empty())
+ {
+ auto announcement = m_announcementQueue.front();
+ m_announcementQueue.pop_front();
+ {
+ CSingleExit ex(m_queueCritSection);
+ DoAnnounce(announcement.flag, announcement.sender, announcement.message, announcement.item,
+ announcement.data);
+ }
+ }
+ else
+ {
+ CSingleExit ex(m_queueCritSection);
+ m_queueEvent.Wait();
+ }
+ }
+}